Signali na razini procesa (pokrenutog programa) su analogni mehanizam sklopovskim prekidima na razini procesora. Služe za obradu nekih asinkronih događaja. Osnovna ideja je kao i kod prekida: proces nešto svoje radi dok se u nekom (neočekivanom) trenutku ne dogodi nešto što treba odmah obraditi. Stoga se pri primitku signala trenutni posao prekida, obrađuje se signal, te nastavlja s prekinutim poslom. Signal ne sadrži dodatne informacije (osim broja signala) - ako su one potrebne, treba ih dohvatiti u obradi signala. Signal procesu može poslati jezgra operacijskog sustava (npr. SIGSEGV), drugi proces (npr. SIGTERM) ili proces sam sebi (npr. SIGALRM uz odgodu ili neki drugi događaj). Proces može programirati svoje ponašanje za signal: - može ga prihvatiti i obraditi pretpostavljenom funkcijom (većinom to znači prekid procesa) - može ga prihvatiti i obraditi funkcijom zadanom u programu (u programu je definirano što će se obaviti po primitku takvog signala) - može ga se zadržati (zapamtiti, ali ne i odmah obraditi) - može ga se ignorirati (odbaciti bez obrade). Izuzetak od navedenih pravila je SIGKILL koji ubija proces (SIGKILL ignorira postavke koje je program postavio).
Kada se prihvati signal, pozove se funkcija za obradu signala. Slično kao i kod prekida na razini procesora, i pri prihvatu signala zabranjuje se daljnje prekidanje, ali samo s tim signalom - drugi signali mogu prekinuti tu obradu. Po završektu obrade ponovno se dozvoljava prekidanje s tim signalom te se eventualno zadržani signali (došli za vrijeme obrade) sada propuštaju. Signali koji se procesu upute za vrijeme obrade prethodnog signala istog tipa - isti broj, stavljaju se u red i čekaju. S time da se pamti samo po jedan signal istog tipa. Primjerice, ako procesu za vrijeme obrade signala SIGINT dođu još tri takva signala, zapamtit će se samo prvi takav signal. Po završetku obrade prvog signala SIGINT ponovno će se pozvati ista funkcija, ali samo jednom (uz prepostavku da za vrijeme ove druge obrade nije došao novi signal SIGINT).
Signali su standardni mehanizam na operacijskim sustavima UNIX i njemu sličnim (npr. Linux). Operacijski sustavi Windows imaju minimalnu podršku za signale i u mnogočemu su različiti (zapravo se oni ne koriste).
Moderne implementacije UNIX-a definiraju oko tridesetak signala. Ovdje je pregled samo istaknutijih signala, dok potpun popis daje man signal:
|
SIGINT (2) |
(interrupt) "prekid", može ga se poslati programu sa Ctrl-C |
|
SIGQUIT (3) |
(quit) "završi (zbog nekih problema) može ga se poslati programu sa Ctrl+\ (na nekim HR tipkovnicama sa Ctrl+Ž) |
|
SIGALRM (14) |
(alarm) koristi se prilikom korištenja funkcije sleep |
|
SIGTERM (15) |
(terminate) traži se od procesa da završi s radom (na redoviti način) |
|
SIGKILL (9) |
(kill) traži se od operacijskog sustava da prekine navedeni proces kome se signal šalje |
Simbolička imena signala nalaze se u biblioteci signal.h.
U nastavku su prikazane "starije" i jednostavnije funkcije za rad sa
signalima (upravo zato jer su jednostavnije). Međutim, pri "ozbiljnom"
korištenju signala treba razmotriti korištenje modernija sucelja (sigaction,
pthread_kill, pthread_sigmask).
Funkcija definira što će se zbiti prilikom primitka određenog signala (maskira signal). Argument signal je broj signala (npr. SIGINT). Drugi argument je kazaljka na funkciju i može biti:
Funkcija
sigset vraća prethodno ponašanje procesa za navedeni signal (ili adresu funkcije kojom se signal obrađivao).void obrada_signala( int signal );
Funkcija za obradu signala treba primiti (minimalno) jedan parametar - broj signala, po kojem se u funkciji može odrediti koji je signal uzrok poziva te funkcije.
Funkcijama sighold i
sigrelse može se zabraniti, odnosno omogućiti prekidanje nekim signalom.Funkcijom kill šalje se signal procesu s
identifikacijskim brojem pid. pid procesa se može vidjeti i
naredbom ps.
U ljusci postoji istoimena naredba kill -signal pid koja
radi isto (šalje signal procesu). Ako treba ubiti neki proces, može se to
učiniti naredbom kill -SIGKILL pid (ili kill -9 pid).
Funkcija zaustavlja rad procesa dok se njemu ne pošalje bilo koji signal. Po primitku signala, najprije se obrađuje taj signal, a potom nastavlja s programom koji slijedi iza pause.
Funkcija alarm(t) programira alarm koji će nakon t sekundi procesu poslati signal SIGALRM. Ako se alarm pozove prije nego li se prethodno postavljeni alarm aktivirao, prethodni se poništava (prepisuje se novim). Ako je t=0, prethodno postavljeni alarm (ako je bilo takvog) se poništava.
Namjena funkcije sleep(t) je odgoditi izvođenje
programa za t sekundi. Medutim, funkcija će biti prekinuta bilo kojim
signalom te, nakon obrade pristiglog signala, program nastavlja nakon poziva
sleep (i odgoda će u tom slučaju biti kraća), a povratna vrijednost će biti
broj "neprospavanih" sekundi.
Primjerice, ako se 5 sekundi nakon poziva sleep(100) procesu pošalje neki
signal (koji se brzo obradi), program će nastaviti s izvođenjem instrukcija
nakon funkcije sleep već nakon tih 5 sekundi, tj. neće spavati još 95
nakon obrade signala! Međutim, funkcija sleep će vratiti vrijednost 95 pa
se ta vrijednost može iskoristiti za dodatnu odgodu:
a = sleep(100);
while( (a = sleep( a )) > 0 );
Odgoda s mogučnošću veće preciznosti je funkcija nanosleep(t). Postoji i funkcija usleep(us) (mikrosekunde), ali se njeno korištenje ne preporuča (smatra se zastarjelom).
Umjesto funkcije sigset može se koristiti i naprednija funckija sigaction. Opis te funkcije dan je i kratkim primjerom.
Kostur programa koji poziva zadanu funkciju prilikom primitka signala SIGINT dan je sljedećim kodom:
#include <stdio.h>
#include <signal.h>
void prekidna_rutina(int sig)
{
/* obrada prekida */
}
int main (void)
{
sigset (SIGTSTP, prekidna_rutina);
printf("Poceo osnovni program PID=%d\n", getpid());
/* troši vrijeme da se ima što prekinuti - 10 s */
printf ("Zavrsio osnovni program\n");
return 0;
}