CATEGORII DOCUMENTE |
Semnalele informeaza procesele despre aparitia evenimentelor asincrone. Procesele isi pot trimite semnale prin intermediul apelului sistem kill, sau nucleul poate trimite intern semnale. Exista 19 semnale in versiunea de UNIX System V care pot fi clasificate dupa cum urmeaza :
Semnale pentru terminarea proceselor, transmise atunci cind un proces executa apelul sistem exit sau cand un proces executa apelul sistem signal cu parametrul 'terminare fiu';
Semnale de atentionare in cazul exceptiilor produse de procese, de exemplu cand un proces acceseaza o adresa in afara spatiului lor virtual de adrese, cand un proces incearca sa scrie in zonele de memorie protejate la scriere (cum ar fi codul programului), cand executa o instructiune privilegiata, sau pentru diferite erori hardware;
Semnale pentru situatii fara iesire aparute in timpul apelurilor sistem, cum ar fi lipsa resurselor in timpul executiei apelului sistem exec dupa ce spatiul initial de adrese fusese eliberat (vezi Paragraful 8.5);
Semnale determinate de conditii de eroare neasteptate aparute in timpul unui apel sistem, cum ar fi executarea unui apel sistem inexistent (procesul a furnizat numarul unui apel sistem care nu corespunde unui apel sistem corect), scrierea unui pipe care nu are proces cititor, sau folosirea unei valori 'referinta' ilegale pentru apelul sistem lseek. Ar fi mult mai comod sa se intoarca o eroare in astfel de situatii in schimbul generarii unui semnal, dar folosirea semnalelor pentru a abandona procesele care nu se comporta corespunzator este mult mai practica (folosirea semnalelor in aceste cazuri suplineste lipsa verificarii erorilor de catre programator in cazul apelurilor sistem) ;
Semnale provenite de la procesele in modul utilizator, de exemplu cand un proces doreste sa receptioneze un semnal alarm dupa un anumit timp, sau cand procesele trimit unul altuia semnale in mod arbitrar, prin intermediul apelului sistem kill;
Semnale provenite de la interactiunea cu un terminal, atunci cand un utilizator intrerupe un terminal, sau cand un utilizator apasa tastele 'break' sau 'delete';
Semnale de urmarire a executiei unui proces.
Tratarea semnalelor difera in funtie de modul in care nucleul trimite un semnal unui proces, modul in care trateaza procesul un semnal si modul in care un proces isi controleaza reactia la aparitia unui semnal. Pentru a trimite un semnal unui proces, nucleul seteaza un bit in campul "semnal" din intrarea tabelei de procese, corespunzator tipului semnalului receptionat. Daca procesul este in asteptare la o prioritate intreruptibila, nucleul il trezeste. Sarcina celui care trimite semnalul (proces sau nucleu) este terminata. Un proces poate memora diferite tipuri de semnale receptionate, dar nu are memorie pentru a pastra numarul de semnale de acelasi tip pe care le-a receptionat. De exemplu, daca un proces receptioneaza un semnal hangup si un semnal kill, acesta seteaza bitii corespunzatori din campul semnal din tabela de procese, dar nu poate spune cate instante ale semnalelor au fost receptionate.
Figura 8.6. Verificarea si tratarea semnalelor in diagrama de stari ale
procesului
Nucleul verifica receptionarea unui semnal cand un proces este gata sa se intoarca din modul nucleu in modul utilizator si cand acesta intra sau paraseste starea de asteptare la o prioritate de planificare scazuta (vezi Figura 8.6). Nucleul trateaza semnalele doar cand un proces se intoarce din modul nucleu in modul utilizator. Astfel, un semnal nu are un efect imediat intr-un proces care ruleaza in modul nucleu. Daca un proces ruleaza in modul utilizator si nucleul trateaza o intrerupere care presupune trimiterea unui semnal catre proces, nucleul va recunoaste si trata semnalul cand se va intoarce din intrerupere. Astfel, un proces nu se va executa niciodata in modul utilizator inainte de tratarea semnalelor importante. Figura 8.7 prezinta algoritmul pe care nucleul il executa pentru a determina daca un proces a receptionat un semnal. Cazul semnalelor de tipul 'terminare fiu' va fi tratat mai tarziu. Asa cum se va vedea, un proces are posibilitatea de a ignora semnalele primite prin intermediul apelului sistem signal. In algoritmul issig, nucleul sterge indicatorii care marcheaza aparitia semnalelor pe care procesul vrea sa le ignore dar noteaza existenta semnalelor pe care acesta nu le ignora.
algoritmul issig /* test pentru receptionarea semnalelor */ intrari: niciuna iesiri: adevarat, daca procesul receptioneaza semnale pe care nu le ignora fals, in celelalte cazuri else if(daca nu ignora semnalul) return (adevarat); sterge bitul semnalului receptionat din campul semnal aflat in tabela de procese; } return (fals); } |
Figura 8.7. Algoritm pentru recunoasterea semnalelor
Nucleul trateaza semnalele in contextul procesului care le receptioneaza, deci un proces trebuie sa ruleze pentru a putea trata semnalele. Exista trei cazuri in tratarea semnalelor: procesul se termina la receptionarea semnalului, acesta ignora semnalul, sau executa o functie particulara (definita de utilizator). Actiunea implicita este de a apela exit in modul nucleu, dar un proces poate specifica o actiune speciala, pe care sa o execute la receptionarea unui anumit semnal cu ajutorul apelul sistem signal.
Sintaxa pentru apelul sistem signal este
oldfunction=signal (signum, function);
unde signum este numarul semnalului pentru care procesul specifica actiunea, function este adresa functiei (utilizator) pe care procesul doreste sa o apeleze la receptia semnalului si valoarea de revenire oldfunction valoarea parametrului function la ultimul apel al lui signal cu parametrul signum. Procesul poate apela signal cu valoarea 1 sau 0 in loc de adresa functiei: procesul va ignora viitoarele aparitii ale semnalului daca valoarea parametrului este 1 (Paragraful 8.4 trateaza cazul special pentru ignorarea semnalului 'terminare fiu') si se termina daca valoarea parametrului este 0 (valoarea implicita). U area contine un sir de campuri pentru tratarea semnalelor, un camp pentru fiecare semnal definit in sistem. Nucleul stocheaza adresa functiei definite de utilizator in campul care corespunde numarului semnalului. Modul de tratare a semnalelor de un anumit tip nu are efect in tratarea semnalelor de alte tipuri.
algoritmul psig /* tratarea semnalelor dupa recunoasterea existentei lor*/ intrari: niciuna iesiri: niciuna if (semnalul este de tipul celor pentru care sistemul trebuie sa creeze o imagine a procesului pentru depanare) apeleaza imediat algoritmul exit; } |
Figura 8.8. Algoritm pentru tratarea semnalelor
Cand trateaza un semnal (figura 8.8) nucleul determina tipul semnalului si sterge bitul semnalului corespunzator din intrarea tabelei de procese, setat cand procesul a receptionat semnalul. Daca functia de tratare a semnalului are valoarea implicita, nucleul va scoate imaginea a procesului pentru anumite tipuri de semnale inainte de terminarea acestora. Aceasta este o facilitate pentru programatori, permitand acestora depaneze programele. Nucleul scoate imaginea procesului pentru semnalele care sugereaza ca ceva este gresit in proces, cum ar fi faptul ca procesul executa o instructiune ilegala sau cand acesta acceseaza o adresa in afara spatiului sau virtual de adrese. Dar nucleul nu scoate imaginea procesului pentru semnalele care nu implica o eroare la executarea programului. De exemplu, receptionarea unui semnal de intrerupere, trimis cand un utilizator apasa tastele 'delete' sau 'break' la terminal, sugereaza ca utilizatorul doreste sa termine prematur un proces iar receptionarea semnalului hangup sugereaza ca terminalul login nu va mai fi 'conectat' pentru mult timp. Aceste semnale nu implica faptul ca ceva este gresit in proces. Semnalul quit, totusi, provoaca scoaterea imaginii procesului chiar daca este initiat din afara. Uzual trimis prin apasarea tastei control + bara verticala, semnalul quit permite programatorului sa obtina o imagine a procesului care se executa, imagine care este folosita cand acesta intra intr-un ciclu infinit.
Cand un proces receptioneaza un semnal pe care anterior a decis sa-l ignore, acesta continua ca si cand semnalul nu ar fi aparut. Deoarece nucleul nu reseteaza campul din u area care arata ca semnalul este ignorat, procesul va ignora semnalul si la aparitia ulterioara a acestuia. Daca un proces receptioneaza un semnal pe care acesta anterior a decis sa-l intercepteze, acesta executa functia de tratare a semnalului specificata de utilizator imediat dupa revenirea in modul utilizator, dupa ce nucleul parcurge urmatorii pasi:
Nucleul acceseaza contextul registru salvat, gasind numaratorul de program si indicatorul de stiva pe care acesta ii salvase pentru revenirea in procesul utilizator.
Acesta sterge campul rutinei de tratare a semnalului din u area, setandu-l la valoarea implicita.
Nucleul creeaza un cadru stiva nou in stiva utilizator, scriind aici valorile numaratorului de program si indicatorului de stiva restabilite din contextul registru salvat si aloca spatiu nou, daca este necesar. Stiva utilizator arata ca si cum procesul a apelat o functie de nivel utilizator (interceptorul de semnale) in punctul in care acesta a facut apelul sistem sau in punctul in care nucleul il intrerupsese (inainte de recunoasterea semnalului).
Nucleul schimba contextul registru salvat: acesta seteaza valoarea numaratorului de programe la adresa functiei de interceptare a semnalului si seteaza valoarea indicatorului de stiva pentru a tine evidenta cresterii stivei utilizatorului.
Dupa intoarcerea din modul nucleu in modul utilizator, procesul va executa functia de tratare a semnalului; cand acesta termina functia de tratare a semnalului, se intoarce in punctul din codul utilizator unde a aparut apelul sistem sau s-a produs intreruperea, imitand o intoarcere din apelul sistem sau intrerupere.
De exemplu, figura 8.9 contine un program care intercepteaza semnale de intrerupere (SIGINT) si isi trimite un semnal de intrerupere (rezultatul apelului kill); figura 8.10 contine partile relevante ale programului dezasamblat pe un VAX 11/780. Cand sistemul executa procesul, apelul la rutina de biblioteca kill se va face la adresa ee (in hexazecimal) si rutina executa instructiunea chmk (schimbarea modului in modul nucleu) la adresa 10a pentru a face apelul sistem kill. Adresa de retur din apelul sistem este 10c.
In timpul executarii apelului sistem, nucleul trimite un semnal de intrerupere catre proces. Nucleul ia in considerare semnalul de intrerupere cand se intoarce in modul utilizator, scoate adresa 10c din contextul registru salvat si o plaseaza in stiva utilizator.
Nucleul ia adresa functiei de interceptare a semnalului (catcher), 104, si o pune in contextul registru salvat. Figura 8.11 ilustreaza starile stivei utilizator si contextul registru salvat.
Exista cateva anomalii in algoritmul descris aici pentru tratarea semnalelor. Prima si cea mai importanta este ca inainte ca un proces sa se intoarca in modul utilizator dupa ce acesta trateaza un semnal, nucleul sterge campul din u area care contine adresa functiei utilizator de tratare a semnalului. Daca procesul doreste sa trateze semnalul din nou, acesta trebuie sa apeleze din nou apelul sistem signal.
Aceasta are din nefericire si alte consecinte: o conditie de concurenta rezulta deoarece a doua instanta a semnalului poate sosi inainte ca procesul sa aiba ocazia sa invoce apelul sistem. Pentru ca procesul este executat in modul utilizator, nucleul ar putea face o comutare de context, crescand sansa ca acesta sa receptioneze semnalul inaintea resetarii interceptorului de semnal.
#include <signal.h> main() catcher() |
Figura 8.9. Codul sursa al programului care intercepteaza semnale
**** DEZASAMBLORUL VAX ****
#main()
e4:
e6: pushab 0x18(pc)
ec: pushl $0x2
# urmatoarea linie apeleaza signal
ee: calls $0x2,0x23(pc)
f5: pushl $0x2
f7: clrl -(sp)
# urmatoarea linie apeleaza rutina de biblioteca kill
f9: calls $0x2,0x8(pc)
100: ret
101: halt
102: halt
103: halt
#catcher()
104:
106: ret
107: halt
#kill()
# urmatoarea linie executa o 'instructiune trap'
(schimba modul in modul nucleu)
10a: chmk $0x25
10c: bgequ 0x6 <0x114>
10e: jmp 0x14(pc)
114: clrl r0
116: ret
Figura 8.10. Dezasamblarea programului care intercepteaza semnale
Figura 8.11. Stiva utilizator inainte si dupa receptionarea semnalului
Programul din figura 8.12 ilustreaza conditia de concurenta. Procesul apeleaza signal pentru a aranja interceptarea semnalului de intrerupere si executa functia sigcatcher. Apoi creeaza un proces fiu, invoca apelul sistem nice pentru a-si micsora prioritatea de planificare relativa la procesul fiu (vezi capitolul 9) si intra intr-un ciclu infinit.
Procesul fiu isi suspenda executia pentru 5 secunde pentru a da procesului parinte posibilitatea sa execute apelul sistem nice si sa-si scada prioritatea. Apoi procesul fiu intra intr-un ciclu, trimitand un semnal de intrerupere (prin apelul sistem kill) procesului parinte in timpul fiecarei iteratii.
Daca apelul sistem kill se termina datorita unei erori, probabil pentru ca procesul parinte nu mai exista, procesul fiu se termina. Ideea este ca procesul parinte ar trebui sa invoce interceptorul de semnale de fiecare data cand acesta receptioneaza un semnal de intrerupere. Interceptorul de semnale tipareste un mesaj si apeleaza din nou signal pentru a intercepta urmatoarea aparitie a unui semnal de intrerupere, si procesul parinte continua sa execute ciclul infinit
#include <signal.h> sigcatcher() main() /* prioritate scazuta, posibilitate mare de aparitie a conditiilor de concurenta */ nice(10); for(;;); } |
Figura 8.12. Program ce demonstreaza conditiile de concurenta in
interceptarea semnalelor
Este posibil sa apara, totusi, urmatoarea secventa de evenimente:
Procesul fiu trimite un semnal de intrerupere procesului
parinte.
Procesul parinte intercepteaza semnalul si apeleaza interceptorul de semnale, dar nucleul intrerupe procesul si comuta contextul inaintea executarii apelului sistem signal.
Procesul fiu se executa din nou si trimite un alt semnal de intrerupere catre procesul parinte.
Procesul parinte receptioneaza al doilea semnal de intrerupere, dar acesta nu a facut setarile pentru a intercepta semnalul. Cand acesta reia executia, se termina.
Programul a fost scris pentru a permite o astfel de comportare, deoarece invocarea apelului sistem nice de catre procesul parinte determina nucleul sa planifice procesul fiu mai des. Totusi este nedeterminat cand va aparea acest efect.
Dupa cum afirma Ritchie, semnalele au fost proiectate ca evenimente care sunt fatale sau se pot ignora, nu in mod necesar ca evenimente care trebuiesc tratate si din acest motiv conditiile de concurenta nu au fost fixate in versiunile anterioare. Cu toate acestea, ele pun serioase probleme programelor care doresc sa intercepteze semnale. Problema ar putea fi rezolvata daca campul semnal nu ar fi sters la receptionarea semnalului. Dar o astfel de solutie ar putea da nastere unei noi probleme: daca semnalele sosesc continuu si sunt preluate, stiva utilizator ar putea creste peste limita admisa datorita numarului mare de apeluri. Ca alternativa, nucleul ar putea reseta valoarea functiei de tratare a semnalului astfel incat acestea sa ignore semnalele de tipul respectiv pana cand utilizatorul precizeaza din nou ce va face cu acestea. O astfel de solutie implica o pierdere de informatie, deoarece procesul nu are cum sa stie cate semnale receptioneaza. Totusi, pierderea de informatie nu este mai severa decat ar fi in cazul in care procesul receptioneaza mai multe semnale de un anumit tip inainte sa le poata trata. In sfarsit, sistemul BSD permite unui proces sa blocheze si sa deblocheze receptionarea unor semnale printr-un apel sistem nou; cand un proces deblocheaza semnalele, nucleul trimite semnalele netratate care au fost blocate catre proces. Cand un proces receptioneaza un semnal, nucleul blocheaza in mod automat receptionarea altor semnale pana la tratarea completa a acestuia. Aceasta metoda este similara modului in care nucleul reactioneaza la intreruperile hardware: acesta blocheaza transmiterea de noi intreruperi in timp ce sunt tratate cele anterioare.
O a doua anomalie in tratarea semnalelor se refera la interceptarea semnalelor care apar in timp ce procesul se afla intr-un apel sistem, asteptand la un nivel de prioritate intreruptibila. Semnalul determina procesul sa execute un apel longjmp din starea de asteptare, sa revina in modul utilizator si sa apeleze functia de tratare a semnalului. Cand aceasta functie se termina, procesul apare ca si cum ar reveni din apelul sistem cu o eroare care indica faptul ca acesta a fost intrerupt.
Utilizatorul poate verifica eroarea intoarsa si relua apelul sistem, dar uneori este mai convenabil daca nucleul face automat acest lucru, asa cum se face in sistemul BSD.
O a treia anomalie apare in cazul in care un proces ignora un semnal. Daca semnalul soseste in timp ce procesul se afla in asteptare pe un nivel de prioritate intreruptibila, procesul se va trezi dar nu va executa un apel longjmp. Aceasta inseamna ca nucleul isi da seama ca procesul ignora semnalul doar dupa ce il trezeste si il executa. O politica mai buna ar fi ca procesul sa fie lasat in asteptare. Cu toate acestea, nucleul memoreaza adresa functiei de tratare a semnalului in u area, si u area nu poate fi accesata atunci cand semnalul este trimis procesului. O solutie la aceasta problema ar fi inscrierea adresei functiei de tratare a semnalului in intrarea din tabela de procese, unde nucleul ar putea verifica daca procesul trebuie trezit la receptionarea unui semnal. Ca o alternativa, procesul ar putea imediat sa se intoarca in starea " asteptare" utilizand algoritmul sleep, daca isi da seama ca nu ar fi trebuit trezit. Cu toate acestea, procesele utilizator nu realizeaza daca procesul a fost trezit, deoarece nucleul mentine intrarea in algoritmul sleep intr-o bucla while (vezi Capitolul 2), punand procesul inapoi in asteptare daca evenimentul pentru care astepta nu a aparut intr-devar.
In sfarsit, nucleul nu trateaza semnalele 'terminare fiu' la fel ca pe celelalte semnale. In particular, cand procesul isi da seama ca a primit un semnal 'terminare fiu', pune pe zero campul semnal din intrarea in tabela de procese si in acest caz actioneaza ca si cum nici un semnal nu ar fi fost transmis. Efectul unui semnal 'terminare fiu' este trezirea unui proces care asteapta pe un nivel de prioritate intreruptibila. Daca procesul intercepteaza un semnal 'terminare fiu', el apeleaza functia de tratare utilizator ca si pentru alte semnale. Operatiile pe care le face nucleul daca procesul ignora semnalele 'terminare fiu', vor fi discutate in paragraful 8.4. In sfarsit, daca un proces invoca apelului sistem signal cu parametrul 'terminare fiu', nucleul trimite procesului apelant un semnal 'terminare fiu' daca acesta are procese in starea zombie. In paragraful 8.4. se vor prezenta conventiile pentru apelul signal cu parametrul 'terminare fiu'.
Desi procesele intr-un sistem UNIX sunt identificate printr-un numar unic (PID), sistemul trebuie sa identifice uneori procesele dupa 'grup'. De exemplu, procesele cu un stramos comun care este un shell de logare in sistem sunt in general inrudite si de aceea toate aceste procese primesc semnale cand un utilizator apasa tastele 'Delete' sau 'Break' sau cand linia catre terminal este intrerupta. Nucleul utilizeaza identificatorul grupului de procese pentru a identifica grupurile de procese inrudite care trebuie sa primeasca un semnal comun la aparitia anumitor evenimente. Acesta salveaza identificatorul grupului de procese in tabela de procese; procesele aflate in acelasi grup au acelasi identificator de grup.
Apelul sistem setpgrp initializeaza numarul de grup pentru un proces si-l seteaza ca fiind egal cu valoarea identificatorului de proces propriu. Sintaxa apelului sistem este:
grp=setpgrp();
unde grp este noul numar al grupului de procese. Un proces fiu retine numarul de grup de procese al procesului parinte in timpul apelului sistem fork. Setpgrp are, de asemenea, importanta in setarea terminalului de control al unui proces (vezi Paragraful 6.3.5.).
Procesele trimit semnale folosind apelului sistem kill. Sintaxa pentru acest apel este:
kill (pid, signum)
unde pid identifica setul de procese care primesc semnalul si signum este numarul semnalului trimis. In lista care urmeaza se arata corespondenta dintre valorile parametrului pid si seturile de procese.
Daca pid este un intreg pozitiv, nucleul trimite un semnal procesului care are identificatorul de proces pid.
Daca pid este 0, nucleul trimite semnal tuturor proceselor din grupul procesului care a trimis semnalul.
Daca pid este -1, nucleul trimite semnalul tuturor proceselor al caror identificator al utilizatorului real este egal cu identificatorul utilizatorului efectiv al procesului care a trimis semnalul (Paragraful 8.6. va defini identificatorul utilizatorului real si efectiv). Daca procesul care trimite semnalul are identificatorul utilizator efectiv al superutilizatorului, nucleul trimite semnalul tuturor proceselor cu exceptia proceselor 0 si 1.
Daca pid este un intreg negativ diferit de -1, nucleul trimite semnalul tuturor proceselor din grupul de procese care au valoarea absoluta egala cu valoarea parametrului pid.
In toate cazurile, daca procesul care trimite semnalul nu are identificatorul utilizatorului efectiv egal cu al superutilizatorului, sau daca identificatorul sau utilizator efectiv sau real este diferit de identificatorul utilizator efectiv sau real al procesului care receptioneaza, kill esueaza.
#include <signal.h>
main()
}
kill(0,SIGINT);
}
Figura 8.13. Exemplu de utilizare a lui Setpgrp
In programul din figura 8.13, procesul schimba numarul sau de grup si creeaza 10 procese fiu. La creare, fiecare proces fiu are acelasi numar de grup cu al procesului parinte, dar procesele create in timpul iteratiilor impare din ciclu isi modifica numarul de grup. Apelurile sistem getpid si getpgrp intorc identificatorul procesului si identificatorul grupului pentru procesul care se executa, iar apelului sistem pause suspenda executia procesului pana cand acesta receptioneaza un semnal. La sfarsit, procesul parinte executa apelul sistem kill si trimite un semnal de intrerupere tuturor proceselor din grupul sau. Nucleul trimite semnalul catre cele 5 procese 'pare' care nu si-au schimbat propriul numar de grup de procese, dar cele 5 procese 'impare' continua ciclul.
Politica de confidentialitate | Termeni si conditii de utilizare |
Vizualizari: 1322
Importanta:
Termeni si conditii de utilizare | Contact
© SCRIGROUP 2024 . All rights reserved