Documente Academic
Documente Profesional
Documente Cultură
Laborator nr. 8
Laborator nr. 8
Semnale Linux/Unix
Important: deci fiecare tip de semnal are asociat o actiune (un handler de semnal)
specifica acelui tip de semnal.
1. Categorii de semnale
In general, evenimentele ce genereaza semnale se impart in 3 categorii: erori,
evenimente externe si cereri explicite.
O eroare inseamna ca programul a facut o operatie invalida si nu poate sa-si
continue executia. Nu toate erorile genereaza semnale (de exemplu: erori in operatiile I/O;
apelul de functie respectiv va intoarce un cod de eroare, de obicei -1), ci doar acele erori
care pot apare in orice punct al programului: impartirea la zero, accesarea unei adrese de
memorie invalide, etc.
Evenimentele externe sunt in general legate de operatiile I/O sau de actiunile altor
procese, cum ar fi: sosirea datelor (pe un socket sau un pipe, de exemplu), expirarea
intervalului de timp setat pentru un timer (o alarma), terminarea unui proces fiu, sau
suspendarea/terminarea programului de catre utilizator (prin apasarea tastelor ^Z sau ^C).
O cerere explicita inseamna generarea unui semnal de catre un proces, prin apelul
functiei de sistem kill(), a carei sintaxa o vom discuta mai jos.
Important: semnalele pot fi generate sincron sau asincron. Un semnal sincron
este un semnal generat de o anumita actiune specifica in program si este livrat (daca nu
este blocat) in timpul acelei actiuni. Evenimentele care genereaza semnale sincrone sunt:
erorile si cererile explicite ale unui proces de a genera semnale pentru el insusi.
Sisteme de Operare
Laborator nr. 8
Sisteme de Operare
Laborator nr. 8
paseaza un pointer la o data acolo unde se asteapta un pointer la o functie, sau daca se
corupe stiva prin scrierea peste sfirsitul unui array de tip automatic.
- SIGSEGV* = signal segmentation violation, semnal sincron generat in caz de
violare a segmentului de memorie, adica procesul incearca sa acceseze o zona de
memorie care nu ii apartine (care nu ii este alocata - apartine altor procese, etc.). Cauze
de producere a acestui eveniment: folosirea pentru acces la memorie a unui pointer NULL
sau neinitializat, ori folosirea unui pointer pentru parcurgerea unui array, fara a verifica
depasirea sfirsitului array-ului.
- SIGBUS* = signal bus error, semnal sincron generat in caz de eroare de
magistrala, ce poate apare tot atunci cind se utilizeaza un pointer NULL sau neinitializat,
numai ca, spre deosebire de SIGSEGV care raporteazaun acces nepermis la o zona de
memorie valida(existenta), SIGBUS raporteaza un acces nepermis la o zona de memorie
invalida: adresa inexistenta, sau un pointer dezaliniat, cum ar fi referirea la un intreg
(reprezentat pe 4 octeti), la o adresa nedivizibila cu 4 (fiecare calculator si S.O. are o
anumita politica de aliniere a datelor).
Observatie: toate aceste semnale au drept actiune implicita terminarea procesului
(cu afisarea unui mesaj de eroare specific) si crearea acelui fisier core.
b) Semnale de terminare:
Sunt folosite pentru a indica procesului sa-si termine executia, intr-un fel sau altul.
Motivul pentru care se folosesc este de a putea "face curat" inainte de terminarea propriuzisa: se pot salva date in fisiere, sterge fisierele temporare, restaura vechiul tip de terminal
in caz ca el a fost modificat de catre program, etc.
- SIGHUP = signal hang-up, semnal generat in momentul deconectarii terminalului
(probabil datorita unei erori in retea), sau la terminarea procesului de control a
terminalului, si este trimis proceselor asociate cu acea sesiune de lucru, avind ca efect
deconectarea efectiva a acestor procese de terminalul de control. Actiunea implicita:
terminarea procesului.
- SIGINT = signal program interrupt, semnal de intrerupere, generat atunci cind
utilizatorul foloseste caracterul INTR (adica: apasa tastele CTRL+C) pentru a termina
executia programului.
- SIGQUIT = signal quit, semnal de intrerupere, generat cind utilizatorul foloseste
caracterul QUIT (de obicei, tastele CTRL+\), fiind asemanator cu semnalul SIGINT:
terminarea procesului.
- SIGTERM = semnal generic, folosit pentru terminarea proceselor; spre deosebire
de SIGKILL, acest semnal poate fi blocat, ignorat, sau sa i se asigneze un handler propriu.
- SIGKILL = signal kill, semnal utilizat pentru terminarea imediata a proceselor; el nu
poate fi blocat, ignorat, sau sa i se asigneze un handler propriu, deci are o comportare fixa
- terminarea procesului, de aceea se spune ca este un semnal fatal. Poate fi generat doar
de evenimentul cerere explicita, folosind apelul kill().
c) semnale de alarma:
Aceste semanle indica expirarea timpului pentru timere si alarme, care pot fi setate
prin apelul primitivelor alarm() si setitimer().
Comportamentul implicit al acestor semnale este terminarea procesului, de aceea
este indicata asignarea de handlere proprii pentru ele.
- SIGALRM = signal time alarm, semnal emis la expirarea timpului pentru un timer
care masoara timpul "real" (=intervalul de timp scurs intre inceputul si sfirsitul procesului).
- SIGVTALRM = signal virtual time alarm, semnal emis la expirarea timpului pentru
un timer care masoara timpul "virtual" (=timpul in care procesul utilizeaza efectiv CPU-ul.
- SIGPROF = semnal emis la expirarea timpului pentru un timer care masoara
timpul in care procesul utilizeaza efectiv CPU-ul si timpul in care CPU-ul asteapta
indeplinirea unor conditii (cereri de I/O) pentru acel proces. Acest tip de semnal se
utilizeaza pentru a implementa facilitati de optimizare a codului programelor.
Sisteme de Operare
Laborator nr. 8
Sisteme de Operare
Laborator nr. 8
scrie. Daca procesul care trebuie sa citeasca nu este startat, sau se termina in mod
neasteptat, atunci scrierea in pipe cauzeaza generarea acestui semnal. Daca procesul
blocheaza sau ignora semnalele SIGPIPE, atunci scrierea in pipe esueaza cu
errno=EPIPE. Actiunea implicita a acestui semnal este terminarea procesului.
- SIGUSR1 si SIGUSR2 = semnale furnizate pentru ca programatorul sa le
foloseasca dupa cum doreste. Sunt utile pentru comunicatia inter-procese.
Actiunea implicita a acestor semnale fiind terminarea procesului, este necesara
asignarea unor handlere proprii pentru aceste semnale. Singurul eveniment care
genereaza aceste semnale este cererea explicita, folosind apelul kill().
Alte semnale:
- SIGTRAP * = signal trap, semnal emis dupa executia fiecarei instructiuni, atunci
cind procesul este executat in modul de depanare.
- SIGIOT * = signal I/O trap, semnal emis in caz de probleme hardware (de
exemplu, probleme cu discul).
- SIGSYS * = semnal emis in caz de apel sistem cu parametri eronati.s.a.
Observatie: o parte din aceste tipuri de semnale depind si de partea de hardware a
calculatorului respectiv, nu doar de partea sa de software. Din acest motiv, exista mici
diferente in implementarea acestor semnale pe diferite tipuri de arhitecturi, adica unele
semnale se poate sa nu fie implementate deloc, sau sa fie implementate (adica, actiunea
implicita asociata lor) cu mici diferente. Exemple de semnale ce pot diferi de la un tip de
arhitectura la altul: cele generate de erori, cum ar fi SIGBUS etc. Astfel, in primele versiuni
de Linux nu era implementat semnalul SIGBUS, deoarece hardware-ul Intel386 pentru
care a fost scris Linux-ul, nu permitea detectarea acelui eveniment descris mai sus,
asociat semnalului SIGBUS.
Lista semnalelor implementate pe Linux se poate obtine folosind comanda: man7
signal , comanda ce va afisa urmatoarea urmatoarele semnale:
Standard Signals
Linux
supports the standard signals listed below. Several signal numbers
architecture dependent, as indicated in the "Value" column.
(Where three values
given, the first one is usually valid for alpha and sparc, the middle one for i386,
and sh, and the last one for mips.
A - denotes that a signal is absent on
corresponding architecture.)
are
are
ppc
the
Sisteme de Operare
Laborator nr. 8
and POSIX.1-2001.
Signal
Value
Action
Comment
------------------------------------------------------------------------SIGBUS
10,7,10
Core
Bus error (bad memory access)
SIGPOLL
Term
Pollable event (Sys V). Synonym of SIGIO
SIGPROF
27,27,29
Term
Profiling timer expired
SIGSYS
12,-,12
Core
Bad argument to routine (SVr4)
SIGTRAP
5
Core
Trace/breakpoint trap
SIGURG
16,23,21
Ign
Urgent condition on socket (4.2BSD)
SIGVTALRM
26,26,28
Term
Virtual alarm clock (4.2BSD)
SIGXCPU
24,24,30
Core
CPU time limit exceeded (4.2BSD)
SIGXFSZ
25,25,31
Core
File size limit exceeded (4.2BSD)
Up to and including Linux 2.2, the default behaviour for SIGSYS, SIGXCPU,
SIGXFSZ, and (on architectures other than SPARC and MIPS) SIGBUS was to terminate the
process (without a core dump). (On some other Unices the default action for SIGXCPU and
SIGXFSZ is to terminate the process without a core dump.)
Linux 2.4 conforms to
the
POSIX.1-2001 requirements for these signals, terminating the process with a core dump.
Next various other signals.
Signal
Value
Action
Comment
-------------------------------------------------------------------SIGIOT
6
Core
IOT trap. A synonym for SIGABRT
SIGEMT
7,-,7
Term
SIGSTKFLT
-,16,Term
Stack fault on coprocessor (unused)
SIGIO
23,29,22
Term
I/O now possible (4.2BSD)
SIGCLD
-,-,18
Ign
A synonym for SIGCHLD
SIGPWR
29,30,19
Term
Power failure (System V)
SIGINFO
29,-,A synonym for SIGPWR
SIGLOST
-,-,Term
File lock lost
SIGWINCH
28,28,20
Ign
Window resize signal (4.3BSD, Sun)
SIGUNUSED
-,31,Term
Unused signal (will be SIGSYS)
(Signal 29 is SIGINFO / SIGPWR on an alpha but SIGLOST on a sparc.)
SIGEMT is not specified in POSIX.1-2001, but nevertheless appears on most
other Unices, where its default action is typically to terminate the process with a core
dump.
SIGPWR (which is not specified in POSIX.1-2001) is typically ignored by
default on those other Unices where it appears.
SIGIO (which is not specified in POSIX.1-2001) is ignored by default on
several other Unices.
Sisteme de Operare
Laborator nr. 8
Sisteme de Operare
Laborator nr. 8
Sisteme de Operare
Laborator nr. 8
In caz de intrerupere, aceste primitive returneaza -1 (mai putin read si write, care
returneaza nr. de octeti cititi/scrisi cu succes), iar variabila errno este setata la valoarea
EINTR. Programatorul va trebui sa reia executia acelui apel in acest caz. O a doua
posibilitate, despre care am discutat mai sus, este reluarea automata a acelui apel de
sistem intrerupt de un semnal pentru care am specificat flag-ul SA_RESTART prin apelul
functiei sigaction().
6. Blocarea semnalelor
Blocarea semnalelor inseamna ca procesul spune S.O.-ului sa nu ii transmita
anumite semnale. Nu este recomandat ca un program sa blocheze semnalele pe tot
parcursul executiei sale, ci numai pe durata executiei unor parti critice ale codului lui.
Astfel, daca un semnal ajunge in timpul executiei acelei parti de program, el va fi livrat
procesului dupa terminarea acesteia si deblocarea acelui tip de semnal.
Modalitati de blocare a semnalelor:
1) cu ajutorul functiei sigprocmask(), utila de exemplu pentru a se bloca
semnalele in timpul modificarii unor variabile globale in programul principal, variabile ce
sunt accesate si de handler-ele de semnal;
2) folosind membrul sa_mask din structura sigaction, atunci cind se doreste
blocarea unor semnale in timpul executiei handler-ului pentru un anumit semnal (cel
pentru care s-a apelat functia sigaction()).
Pentru blocarea unor semnale in timpul executiei unui handler, o a doua alternativa
este folosirea functiei sigprocmask() in codul handler-ului; in acest caz, insa, exista
totusi o scurta perioada de timp, intre lansarea in executie a handler-ului si executia
Sisteme de Operare
Laborator nr. 8
Functia verifica daca semnalul id-semnal face parte din setul de semnale
definit de variabila set.
Toate functiile de mai sus returneaza valoarea 0, in caz de succes (exceptie:
sigismember returneaza 1 sau 0 = rezultatul testului), respectiv -1, in caz de eroare (si
atunci errno este setata la EINVAL).
b) Functia care blocheaza efectiv un set de semnale:
int sigprocmask(int mod, const sigset_t *set, sigset_t *old_set);
Aceasta functie este folosita pentru a examina sau modifica masca de semnale a
procesului. Colectia(setul) de semnale care sunt la un moment dat blocate se numeste
masca de semnale a procesului.
Parametrul set reprezinta setul de semnale ce vor fi blocate/deblocate.
Parametrul mod determina modul in care va fi modificata masca de semnale, si
poate avea urmatorele valori:
- SIG_BLOCK = blocheaza setul de semnale definit de variabile set, adaugindu-l la
masca de semnale (blocate) deja existenta. (Adica: masca de semnale := masca de
semnale "reuniune" set )
- SIG_UNBLOCK = deblocheaza setul de semnale definit de variabile set, scotindu-l
din masca de semnale (blocate) deja existenta. (Adica: masca de semnale := masca de
semnale "diferenta" set )
- SIG_SETMASK = inlocuieste vechea masca de semnale cu setul de semnale
definit de variabile set.(Adica: masca de semnale := set )
Al treilea parametru, old_set, este utilizat pentru a returna vechea masca de
semnale (lucru util daca, ulterior in program, dorim sa o restauram).
Daca nu se doreste pastrarea vechii masti de semnale, old_set poate fi pointerul
NULL. Iar daca se doreste doar obtinerea mastii de semnale, fara a o modifica, atunci set
va fi pointerul NULL.
Functia returneaza: 0, in caz de succes, respectiv -1, in caz de esec (si errno este
setata corespunzator: EINVAL, EFAULT sau EINTR).
Observatie: daca functia sigprocmask() deblocheaza un anumit tip de semnale
si exista deja in coada cel putin un semnal de acel tip ce asteapta sa fie livrat, el va fi
transmis procesului inainte de terminarea executiei codului functiei sigprocmask().
Sisteme de Operare
Laborator nr. 8
Sisteme de Operare
Laborator nr. 8
}
staticvoidsig_quit(intsig)
{
printf("ReceptionatsemnalulSIGQUIT\n");
if(signal(SIGQUIT,SIG_DFL)==SIG_ERR)
err_sys("Nusepoateresetaacestsemnal...");
return;
}
staticvoidsig_intr(intsig)
{
printf("ReceptionatsemnalulSIGINT\n");
if(signal(SIGINT,sig_intr)==SIG_ERR)
err_sys("Nusepoaterearmaacestsemnal...");
return;
}
staticvoidsig_usr1(intsig)
{
printf("ReceptionatsemnalulSIGUSR1\n");
alarm(1);
printf("Alarmasevadeclansadupa1sec!.\n");
return;
}
Sisteme de Operare
Laborator nr. 8
jmp_bufcs_stack;
intin_reg,s_inreg;
voidbeg_reg();/*functiecemarcheazainceputulregiunii*/
voidend_reg();/*functiecemarcheazasfarsitulregiunii*/
inttratare();/*rutinadetratareasemnalului*/
intread_line();
voidmain()
{
intnr_car;
charbuff[MAXLIN];
signal(SIGINT,tratare);
if(setjmp(cs_stack)){/*prelucrareintrerupere*/
printf("Programulesteintreruptprinsemnal!\n");
exit(1);
}else
while(1){
printf(">");
beg_reg();
nr_car=read_line(buff);
end_reg();
if(nr_car>0){
printf("%s\n",buff);
sleep(2);
}
elsebreak;
}
printf("Programterminatnormal!\n");
}
inttratare()
{
if(in_reg){
signal(SIGINT,SIG_IGN);
s_inreg=1;
return0;
}else{
signal(SIGINT,tratare);
longjmp(cs_stack,1);
}
return0;
}
voidbeg_reg(void)
{
in_reg=1;s_inreg=0;
}
voidend_reg(void)
{
in_reg=0;
if(s_inreg){
s_inreg=0;
signal(SIGINT,tratare);
longjmp(cs_stack,1);
}
}
intread_line(buff)
char*buff;
{
charc;
inti=0;
for(c=getchar();i<MAXLIN&&c!='\n';c=getchar())
buff[i++]=c;
buff[i]='\0';
returni;
Sisteme de Operare
Laborator nr. 8
9.Bibliografie:
Iosif Ignat, Adrian Kacso, UNIX Gestionarea Proceselor, Ed. Albastr, 2006
W. Richard Stevens, Stephen A. Rago, Advanced Programming in the UNIX Environment: Second Edition, Addison Wesley, 2005
Kurt Wall, Mark Watson, and Mark Whitis, Linux Programming Unleashed, Sams
Publishing, 1999
A. D. Marshall, Programming in C. UNIX System Calls and Subroutines using C,
http://www.cs.cf.ac.uk/Dave/C/