Signali

 

Signale su softverski prekidi koji se dostavljaju procesima. Svi procesi koji se izvršavaju reagiraju na signale koje im šalje jezgra operacijskog sustava. Operacijski sustav koristi signale kako bi procesu dojavio da se dogodila neka iznimna situacija. Takav signal može biti proizveden od same jezgre, proces ga može poslati sam sebi ili drugom procesu, ili ga može poslati korisnik. Signali su klasični primjer nesinkronih događaja, jer se mogu pojaviti u bilo koje vrijeme u procesu.

 

Brojni uvjeti mogu izazvati kreiranje signala:

·         Softverski uvjeti generiraju signal kad se dogodi nešto čega bi proces trebao biti svjestan, npr. kada sat alarma postavljen od strane procesa istekne.


Signal može biti poslan u bilo kojem trenutku, ali uvijek ne mora biti primljen niti procesi koji ga prime ne moraju uvijek reagirati na njega. Signal ne sadrži nikakve informacije i može biti poslan samo određenom procesu ili procesima. Signali se nikada ne koriste za normalnu komunikaciju, nego samo za posebne događaje.

 

Kada se signal genrira on postaje neriješen (u toku, eng. pending) i takav ostaje neko kratko vrijeme dok ne bude dostavljen procesu kojem je namijenjen. Međutim, moguće je da je takav signal trenutno blokiran od strane sustava, pa može ostati neriješen proizvoljno dugo, tj. sve do onog trenutka dok ta vrsta signala ne bude deblokirana. Jednom deblokiran dostavlja se odmah.  Postoje tri stvari koje proces može reći jezgri što da učini s dostavljenim signalom:

 

  1. Ignorirati signal. Ovo radi za većinu signala osim za dva signala koja nikad ne mogu biti ignorirana: SIGKILL i SIGSTOP. Razlog zašto ova 2 signala ne mogu biti ignorirana leži u činjenici da superuseru mora biti omogućena opcija sigurnog zaustavljanja ili ubijanja procesa. Također ako ignoriramo neke signale koji su generirani usljed hardverdske pogreške ponašanje procesa nije definirano
  2. Uhvatiti signal. Da bi ovo uradili, jezgri treba reći da pri pojavi signala pozove neku određenu funkciju u kojoj možemo uraditi prouizvoljnu akciju.
  3. Pustiti da se dogodi defaulana akcija. Svaki signal ima svoju defaultnu akciju[1]. Većinom je ta akcija prekidanje rada procesa.

 

 

Vrste signala:

Različiti operativni sustavi definiraju različite signale. Svaki signal ima ime. Imena svih signala počinju sa SIG, a popis svih signala u pojedinom operativnom sustavu može se nađi u datoteci signal.h. Imena signala su pozitivne cjelobrojne konstante.

ANSI C standard specificira sljedećih 6 signala: SIGINT[2] , SIGILL , SIGFPE, SIGSEGV, SIGTERM, SIGABRT..

 

Moderne implementacije UNIX-a definiraju oko tridesetak signala. Ovdje je pregled samo najznačajnijih

SIGINT        Šalje se svakom procesu za koji je to kontrolni terminal u trenutku kada je pritisnuta tipka za prekid (standardno DEL, najčešće izmijenjeno u Ctrl-C).

SIGQUIT       Slično kao SIGINT, ali se odnosi na tipku za kraj izvršavanja (standardno Ctrl-\, najčešće izmijenjeno u Ctrl-X).

SIGKILL       Jedini siguran način uništavanja procesa je da mu se pošalje ovaj signal, jer ne može biti ignoriran niti uhvaćen.

SIGALRM       Šalje se kada istekne traženo vrijeme čekanja procesa.

SIGTERM       Ovo je standardni signal za uništavanje procesa. Koristi se i kod rušenja operacijskog sustava da ubije sve aktivne procese. Očekuje se da će proces koji ga primi spremiti svoje aktualno stanje i zatvoriti otvorene datoteke prije završetka.

SIGFPE        Signal koji se događa zbog aritmetičke pogreške (dijeljenje s nulom, floating point overflow ili underflow)

SIGUSR1 i SIGUSR2 signali slobodni u korisničke svrhe

Rukovanje signalima

Funkcija kojom možemo promijenit defaultno ponašanje signala, te uhvatiti signal i proizvoljno ga obraditi je funkcija signal (i dio je ANSI C-a). Prototip funkcije je:

                                         void (*signal (int, void (*)(int))) (int);[3]
 

Nekoliko objašnjenja:

Primjer: hvatanje signala za kraj programa, primjer za hvatanje aritmetičkih pogrešaka, primjer sa funkcijom alarm, primjer sa dva procesa i signalima.

 

Funkcija signal ima određene mane. Na starijim verzijama UNIX-a nije bila dobro implementirana, tako je prilikom svakog poziva signal handlera, trebalo ponovo postaviti signal handler. Druga mana, tj. nedostatak je bio da je ponekad bilo poželjno na neko vrijeme blokirati mogućnost dostavljanja signala[4] što je zahtjevalo malo drugačiju implementaciju signala.[5]

 

Svaki proces ima signalnu masku koja definira skup signala trenutno blokiranih od strane procesa. Možemo to predočiti na način da svaki bit sadrži predstavlja pojedini signal S obzirom da broj signala može biti veći nego cijeli broj POSIX.1 definira novi tip sigset_t koji sadržava skup signala.

 

Funkcije za manipulacije skupom signala

 

int sigemptyset(sigset_t *set);

int sigfillset(sigset_t *set);

int sigaddset(sigset_t *set, int signo);

int sigdelset(sigset_t *set, int signo);

                                               sve vraćaju 0 ako je OK, -1 u slučaju greške

int sigismember(const sigset_t *set, int signo);

vraća 1 ako je istina , 0 inače

 

int sigprocmask(int how, const sigset_t *set, sigset_t *set);

                                               vraća 0 ako je OK, -1 u slučaju greške

 

sigproc mask ispituje ili postavlja (ili oboje) signalnu masku. Ako je oset nenull pointer, trenutna signalna maska se vraća preko oset. Ako je set ne-null pointer tada how određuje kako je se signlna maska modificirati. Mogućnosti su:

 

SIG_BLOCK

Nova signlna maska za proces je unija trenutne signalne maske i skupa signala definiranog sa set, tj. set sadrži signale koje želimo blokirati.

SIG_UNBLOCK

Nova signlna maska je presjek trenutne signalne maske i skupa signala definiranog sa set, tj. set sadrži signale koje želimo deblokirati

SIG_SETMASK

Postavlja se nova signalna maska.

 

U slučaju da je set null pointer, signalna maska se ne mijenja i vrijednost od how je zanemariva.

 

int sigfillset(sigset_t *set); vraća 0 ako je OK, -1 u slučaju greške

Služi za dobivanje skupa signala koji su blokirani i čekaju dostavljanje.[6]

int sigaction(int signo, const struct sigaction *act,

struct sigaction *oldact);

vraća 0 ako je OK, -1 u slučaju greške

 

Ova funkcija nasljeđuje funkciju signal i služi za ispitivanje ili modificiranje (ili oboje)

 

struct sigaction{

     void (*sa_handler)(); /*adresa signal handlera ili SIG_IGN ili SIG_DFL*/

     sigset_t sa_mask; /*dodatni signali koje treba blokirati*/

     int sa_flags; /*signale opcije npr. SA_RESETHAND */

}

 

int sigsuspend(const sigset_t *sigmask);         vraća -1 i postvlja errno na EINTR

Signalna maska procesa se postavlja na sigmask i proces se zaustavlja dok se ne pojavi signal (malo neprecizno rečeno: unlock and pause)

 

Primjer: blokiranje pojedinih signala

 

Primjer:

Napisati program koji omogućava obradu prekida sa više razina prekida. Struktura prekidne rutine dana je sljedećim pseudokodom:

 

prekidna_rutina  /* pokreće se pojavom prekida uz zabranu daljih prekida */

   ispiši_vrijeme_ulaska_u_prekidnu_rutinu_s_točnošću_na_sekundu();

   odredi uzrok prekida, tj. indeks i

   postavi OZNAKA_ČEKANJA[i]

   dok j takav da je (OZNAKA_ČEKANJA[j]<>0 j>TEKUĆI_PRIORITET) čini

      izaberi najveći j

      izbriši OZNAKA_ČEKANJA[j]

      spremi TEKUĆI_PRIORITET u PRIORITET[j]

      proglasi TEKUĆI_PRIORITET = j

      omogući prekidanje

      obrada_prekida(j)

      zabrani prekidanje

      vrati TEKUĆI_PRIORITET iz PRIORITET[j]

   omogući prekidanje

kraj.

 

UNIX ne dozvoljava pojedinom korisniku izravno korištenje prekida procesora. Zato prekide treba simulirati koristeći signale koje jezgra operacijskog sustava šalje procesima.

 



[1] (Detaljnije o ponašanju pojedinih signala na http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_461.html do  http://www.gnu.org/manual/glibc-2.2.3/html_node/libc_467.html) uz napomenu da se radi o GNU C library.

 

[2]Iz MSDN-a:  SIGINT is not supported for any Win32 application including Windows NT and Windows 95. When a CTRL+C interrupt occurs, Win32 operating systems generate a new thread to specifically handle that interrupt. This can cause a single-thread application such as UNIX, to become multithreaded, resulting in unexpected behavior.

[3] sličnu ulogu na UNIX Version7 i SystemV imala je srodna funkcija sigset.

[4] Korisno kod tzv. 'sporih' sistemskih poziva. Neki od njih se restaraju nakon obrade signala, neki ne (npr. malloc, free, tj. oni koji koriste statičke strukture ili su dio standardne I/O biblioteke)

[5] SistemV pružao je funkcije sighold i sigrelse, ali one nisu dio POSIX.1 standarda

[6] POSIX.1 ne specificira što se događa ako se blokirani signal generira nekoliko puta. Većina UNIX sustava dostavi u tom slučaju samo jedan signal.