De ce multe programe Unix folosesc semnale precum USR1? Semnale de încredere
Semnalele sunt întreruperi software. Ele sunt utilizate pentru comunicarea între procese în UNIX și UNIX-like sisteme de operare precum Linux, Mac OS.
Semnalele au fost utilizate de la Bell Labs UNIX în 1970 și sunt acum definite oficial de standardul POSIX. Când un semnal este primit de un proces, sistemul de operare întrerupe fluxul normal de execuție al procesului și oferă notificare.
Indiferent de sistemul de operare pe care îl utilizați, fără îndoială veți simți că aplicațiile dvs. sunt blocate și refuză să funcționeze corect. În Unix, Linux, există o comandă „kill” pe care o puteți folosi pentru a opri procesul imediat, dar nu numai asta, dar voi vorbi despre asta puțin mai târziu. În acest articol „Kill Command în Unix/Linux” vă voi spune și vă voi arăta exemple gata făcute diverse comenzi ale utilitarului kill.
Ucideți comenzi și semnale
Când lansați comanda kill, de fapt trimiteți un semnal către sistem și îi instruiți să închidă aplicația defectă. Există un total de 60 de semnale care pot fi utilizate, dar tot ce trebuie să știți sunt SIGTERM (15) și SIGKILL (9).
Puteți vizualiza toate semnalele folosind comanda:
# ucide -l
Pe MacOS-ul meu:
Voi încerca să vorbesc despre toate semnalele, dar mai întâi vom vorbi doar despre cele mai importante și frecvent utilizate.
Semnale de bază
Următoarele semnale fac parte din standardul POSIX. Fiecare semnal este o macro definită în
SIGTERM– Acest semnal solicită oprirea unui proces care rulează. Acest semnal poate fi ignorat. Procesul are timp să se închidă bine. Când un program se închide bine, înseamnă că i s-a acordat timp să-și salveze progresul și să elibereze resurse. Cu alte cuvinte, nu a „forțat” procesul să se încheie.
SIGKILL– Semnalul SIGKILL face ca procesul să înceteze imediat să-și facă treaba. Programul nu poate ignora acest semnal. Progresul nesalvat se va pierde.
Sintaxă pentru „kill”.
Sintaxa comenzii este:
# ucide PID(uri)
# kill [-s] [-l] %pid
Semnalul implicit (dacă nu este specificat) este SIGTERM. Când acest semnal nu ajută și nu funcționează, puteți utiliza următoarele opțiuni pentru „ucidere” pentru a opri procesul:
# ucide pe SIGKILL PID
# ucide -9 PID
unde „-9” este steagul care se referă la semnalul SIGKILL.
Dacă nu știți ce PID să utilizați pentru aplicația de care doriți să scăpați, atunci rulați comanda:
$ps -aux
Și dacă știi aplicație specifică(de exemplu, apache), atunci puteți elimina ceea ce este inutil și puteți afișa toate procesele pentru acest serviciu:
$ ps -aux | grep apache
Și va afișa totul rulează aplicațiiîmpreună cu PID-urile sale.
De exemplu, pentru a ucide o aplicație, rulez următoarea comandă:
# ucide -9 3629
De asemenea, merită remarcat faptul că puteți rula mai multe procese în același timp, astfel încât acestea să poată fi „omorâte”:
# kill -9 PID1 PID2 PID 3
Reîncărcați fișierele de configurare sau reporniți utilitățile:
# kill -1 număr_de_PID
Semnalele deosebit de utile includ HUP, INT, kill, STOP, CONT și 0.
Opțiunile sunt:
-s nume_semnal
Un nume de semnal simbolic care specifică semnalul pentru a trimite un semnal care nu este implicit.
-l
Dacă operandul nu este specificat, atunci afișați numele semnalelor; În caz contrar, scrieți numele semnalului corespunzător lui exit_status.
-nume_semnal
Nume simbolic de semnal care specifică semnalul care trebuie trimis către TERM în mod implicit.
-număr_semnal
Un întreg zecimal nenegativ care specifică semnalul implicit de trimis către TERM.
Următoarele PID-uri au o semnificație specială:
-1
Dacă superutilizatorul, atunci transmite semnalul către toate procesele; altfel difuzează la toate procesele aparțin-
ing pentru utilizator.
Unele dintre cele mai frecvent utilizate semnale sunt:
- 1 HUP (închidere) - închide.
- 2 INT (întrerupere) - întrerupere.
- 3 QUIT (renunț) - ieșire.
- 6 ABRT (avortare) - întreruperi.
- 9 KILL (ucidere care nu se poate prinde, nu se poate ignora)
- 14 ALRM (ceas cu alarmă) - ceas cu alarmă.
- 15 TERM (semnal de terminare software) — Software pentru a opri semnalul.
PKill
Comanda „pkill” vă permite să utilizați modele avansate de expresii regulate și alte criterii de potrivire. În loc să utilizați PID-ul, acum puteți închide aplicația introducând numele procesului. De exemplu, pentru a opri browserul Firefox, pur și simplu rulați comanda:
#pkill Firefox
Pentru că se potrivește cu modelul expresie uzuala, puteți introduce și o parte din numele procesului, astfel:
#pkillfire
Pentru a evita „uciderea” proceselor greșite, puteți face „pgrep -l [nume_proces]” pentru a enumera procesele eligibile.
Comanda pkill are mult mai multe opțiuni, de exemplu, dacă specificați opțiunea „-u”, vă va permite să specificați un nume de utilizator sau un ID. În acest exemplu, trimitem semnalul TERM către toate procesele deținute de utilizatorul „nimeni”:
# pkill -u nimeni
Omoara-i pe toti
Killall folosește numele procesului în loc de PID și „ucide” toate instanțele procesului cu același nume. De exemplu, dacă rulați mai multe instanțe ale browserului Firefox, le puteți opri pe toate cu comanda:
#killallfirefox
În Gnome, puteți reporni Nautilus cu comanda:
#killallnautilus
xkill
Xkill este grafic„ucide” aplicația. Când introduceți „XKill” în terminal, cursorul mouse-ului va deveni imediat o „cruce”. Tot ce trebuie să faceți este să apăsați „cruce” pe aplicația ofensă și aceasta va ucide instantaneu aplicația. Dacă sunteți interesat, puteți adăuga o comandă rapidă de la tastatură pentru a activa funcția XKill.
Alte semnale care sunt folosite
SIGABRT
Acest semnal trimite un semnal procesului pentru a anula operația. ABRT este de obicei direcționat către procesul în sine atunci când apelează funcția abort() a limbajului de programare C pentru a semnala o terminare anormală, dar poate fi direcționat de la orice proces la fel ca orice alt semnal.
SIGALRM, SIGVTALRM și SIGPROF
Semnalul ALRM, VTALRM și/sau PROF este trimis unui proces atunci când o limită de timp specificată de un apel la o funcție de alarmă (cum ar fi setitimer) a expirat.
ALRM
Trimis când trece ora actuală sau ceasul.
VTALRM
Trimis când timpul CPU utilizat de un proces a expirat.
PROF
Trimis atunci când timpul CPU utilizat de un proces și sistemul în numele procesului expiră.
SIGBUS
Un semnal BUS este trimis unui proces atunci când are ca rezultat o eroare de magistrală. Condiții care au ca rezultat acest semnal, cum ar fi nealinierea accesului la memorie sau lipsa unei adrese fizice.
SIGCHLD
Semnalul CHLD este trimis unui proces atunci când un proces copil se termină, este întrerupt sau reia după ce a fost întrerupt. O utilizare comună a unui semnal este de a semnala sistemului de operare să curețe resursele care sunt utilizate de un proces copil după ce acesta se termină, fără un apel de sistem explicit.
SIGCONT
Semnalul CONT instruiește sistemul de operare să repornească un proces care a fost suspendat anterior de semnalul STOP sau TSTP. Una dintre caracteristicile importante ale acestui semnal este controlul operațiunii în shell-ul Unix.
SIGFPE
Semnalul FPE este trimis unui proces atunci când efectuează operații aritmetice eronate, cum ar fi împărțirea la zero.
SUPRAȚI
Semnalul HUP este trimis unui proces atunci când terminalul său de control este închis. A fost conceput inițial pentru a notifica un proces după căderile succesive ale liniilor (HUP responsabil pentru blocări). ÎN sisteme moderne, acest semnal înseamnă de obicei că controlul terminalului pseudo sau virtual a fost închis.
SIGILL
Semnal ILL trimis unui proces atunci când încearcă să execute comenzi (instrucțiuni) rău intenționate, necunoscute sau privilegiate.
SIGINT
Semnalul INT este trimis unui proces de la terminalul de control atunci când utilizatorul dorește să încheie procesul. Acest lucru este de obicei inițiat prin apăsarea Control-C, dar pe unele sisteme, „șterge” sau „break”.
SIGKILL
Semnalul KILL este trimis unui proces pentru a opri imediat rularea. Spre deosebire de SIGTERM și SIGINT, acest semnal nu poate fi captat sau ignorat, iar procesul de recepție nu poate efectua nicio curățare după primirea acestui semnal.
SIGPIPE
Semnalul PIPE este trimis unui proces atunci când încearcă să scrie într-o țeavă fără un proces conectat la celălalt capăt.
SIGQUIT
Semnalul QUIT este trimis unui proces de la terminalul său de control atunci când utilizatorul solicită procesului să efectueze o descărcare.
SIGSEGV
Semnalul SEGV este trimis unui proces atunci când face o referință nevalidă memorie virtuala sau o eroare de segmentare, adică atunci când efectuează o încălcare a segmentării.
SIGSTOP
Semnalul STOP îi spune sistemului de operare să oprească procesul, astfel încât să poată fi reluat mai târziu.
SIGTERM
Semnalul TERM este trimis unui proces pentru a solicita terminarea acestuia. Spre deosebire de semnalul „ucidere”, acesta poate fi interpretat sau ignorat în timpul procesului. Acest lucru permite procesului să efectueze o execuție „drăguță” pentru a opri eliberarea de resurse și pentru a salva starea dacă este necesar. Trebuie remarcat faptul că SIGINT este aproape identic cu SIGTERM.
SIGTSTP
Semnalul TSTP este trimis procesului terminalului său de control și îi spune să se suspende temporar. Acest lucru este de obicei inițiat de utilizator prin apăsarea Control-Z. Spre deosebire de SIGSTOP, acest proces poate înregistra un handler de semnal sau poate ignora semnalul.
SIGTTIN și SIGTTOU
Semnalele TTIN și TTOU sunt trimise unui proces atunci când încearcă să citească sau să scrie, respectiv, de la un terminal (tty) în fundal. De regulă, acest semnal poate fi obținut numai folosind procese sub control panou de lucru; demonii nu au terminale de control și nu ar trebui să primească niciodată acest semnal.
SIGUSR1 și SIGUSR2
Semnalele USR1 și USR2 sunt trimise procesului și indică condiții definite de utilizator.
SIGPOLL
Semnalul POLL este trimis unui proces atunci când are loc un eveniment I/O asincron.
SIGSYS
Semnalul SYS este trimis unui proces atunci când transmite un argument prost unui apel de sistem.
SIGTRAP
Un semnal TRAP este trimis unui proces atunci când apare o condiție despre care depanatorul a cerut să fie informat - de exemplu, atunci când o anumită funcție este executată sau când o anumită valoare a unei variabile se modifică.
SIGURG
Semnalul URG este trimis unui proces atunci când priza are date urgente sau în afara intervalului disponibile pentru citire.
SIGXCPU
Semnalul XCPU este trimis unui proces atunci când folosește CPU pentru o perioadă de timp care depășește un anumit punct de referință stabilit de utilizator. Sosirea semnalului XCPU asigură că procesul salvează rapid toate rezultatele intermediare și iese cu mult înainte de a fi ucis de sistemul de operare cu un semnal SIGKILL.
SIGXFSZ
Semnalul XFSZ este trimis în proces atunci când un fișier crește (depășește o valoare specificată) decât valoarea maximă permisă.
SIGRTMIN la SIGRTMAX
Semnalele RTMIN - RTMAX sunt destinate utilizării în scopuri personalizate. Sunt semnale în timp real.
Semnale diferite
Următoarele semnale nu sunt standardizate de POSIX, dar sunt uneori folosite pe unele sisteme.
SIGEMT
Semnalul EMT este trimis în proces atunci când are loc o întrerupere a emulatorului.
SIGINFO
Semnalul INFO este trimis în curs când o solicitare de stare este primită de la terminalul de control.
SIGPWR
Semnalul PWR este trimis în proces atunci când sistemul se confruntă cu o pană de curent.
SIGLOST
Semnalul LOST este trimis unui proces atunci când „blocarea fișierului” este pierdută.
SIGWINCH
Semnalul WINCH este trimis unui proces atunci când terminalul său de control își schimbă dimensiunea.
Trimiterea semnalelor de la tastatură
Semnalele pot fi trimise de la tastatură. Mai jos sunt enumerate mai multe valori standard standard. În mod implicit, comenzile rapide de la tastatură pentru trimiterea semnalelor de întrerupere pot fi definite folosind comanda stty.
CTRL-C
Trimiteți SIGINT (întrerupere). În mod implicit, acest lucru determină încheierea procesului.
CTRL-Z
Trimiteți SIGTSTP (Suspend). În mod implicit, acest lucru face ca procesul să suspende toate operațiunile.
CTRL-\
Trimiteți SIGQUIT (Ieșire). În mod implicit, acest lucru face ca procesul să se termine imediat și să resetați nucleul.
CTRL-T
Trimiteți SIGINFO (INFO). În mod implicit, acest lucru face ca sistemul de operare să afișeze informații despre comandă. Nu este acceptat pe toate sistemele.
concluzie
Când aplicațiile se comportă prost și provoacă înghețarea sistemului, este foarte tentant să reporniți computerul și să începeți din nou sesiunea. Cu aceste comenzi „kill”, puteți gestiona mai bine comportamentul defectuos al aplicațiilor care cauzează sau pot provoca o blocare a sistemului. Cu aceasta, închei acest subiect „Comanda kill în Unix/Linux”.
Semnale de încredere
Standardul POSIX. 1 definit set nou funcții de gestionare a semnalului. bazat pe interfața UNIX 4.2BSD și lipsit de dezavantajele discutate mai sus.
Modelul de semnalizare POSIX se bazează pe concept set de semnale(set de semnal) descris tip variabil sigset_t . Fiecare bit al acestei variabile reprezintă un semnal. Pe multe sisteme, tipul sigset_t are o lungime de 32 de biți, limitând numărul de semnale posibile la 32.
Următoarele funcții vă permit să gestionați seturile de semnale:
#include
int sigempyset(sigset_t *set);
int siufillset(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
int sigdelset(sigset_t *set, int signo);
int sigismember(sigset_t *set, int signo);
Spre deosebire de funcție semnal (3C), schimbând dispoziția semnalelor, aceste funcții vă permit să modificați structura de date sigset_t definită de proces. Pentru a controla semnalele direct, acestea sunt utilizate funcții suplimentare, pe care ne vom uita mai târziu.
Funcţie sigemptyset(3C) inițializează setul ștergând toți biții. Dacă un proces sună sigfillset(3C), atunci setul va include toate semnalele cunoscute de sistem. Funcții sigaddset(3C)Și sigdelset(3C) Vă permite să adăugați sau să eliminați tonuri de apel. Funcţie sigismember(3C) vă permite să verificați dacă specificat de parametru semn semn de setat.
În loc de o funcție semnal (3C) Standardul POSIX. 1 definește o funcție sigatie(2), care vă permite să setați dispoziția semnalelor, să aflați valoarea actuală a acestuia sau să faceți ambele în același timp. Funcția are următoarea definiție:
#include
int sigaction (int sig, const struct sigaction *act,
struct sigaction *oact);
Toate informațiile necesare pentru gestionarea semnalului sunt transmise printr-un pointer către structura sigaction, care are următoarele câmpuri:
Câmpul sa_handler specifică acțiunea de întreprins atunci când semnalele sunt recepționate și poate lua valorile SIG_IGN , SIG_DFL , sau adresa funcției de handler. Dacă sa_handler sau sa_sigaction nu este NULL, atunci câmpului sa_mask i se transmite un set de semnale care vor fi adăugate la masca de semnal înainte de a apela handler-ul. Fiecare proces are instalată o mască de semnal care definește semnalele a căror livrare ar trebui blocată. Dacă este setat un anumit bit de mască, semnalul corespunzător va fi dezactivat. După ce funcția de gestionare revine, valoarea măștii este returnată la valoarea inițială. Rețineți că semnalul pentru care este setată funcția de gestionare va fi, de asemenea, blocat înainte de a fi apelat. Această abordare asigură că în timpul procesării, sosiri ulterioare ale anumitor semnale vor fi suspendate până la finalizarea funcției. De obicei, UNIX nu acceptă cozi de semnale, ceea ce înseamnă că blocarea mai multor semnale de același tip va duce în cele din urmă la livrarea unuia singur.
Câmpul sa_flags definește steaguri care modifică livrarea semnalului. Poate lua următoarele valori:
SA_ONSTACK | Dacă este definită o funcție de gestionare a semnalului, și folosind funcția sigaltstack(2) Dacă este specificată o stivă alternativă pentru funcția de gestionare, atunci această stivă va fi utilizată la procesarea semnalului. Dacă flag-ul nu este setat, va fi folosit stiva normală a procesului. |
SA_RESETHAN * | Dacă este definită o funcție de handler, dispoziția semnalului va fi schimbată în SIG_DFL și semnalul nu se va bloca când handlerul rulează. Dacă steagul nu este setat, dispoziția semnalului rămâne neschimbată. |
SA_NODEFER * | Dacă este definită o funcție de gestionare, semnalul este blocat pe durata procesării numai dacă este specificat în mod explicit în câmpul sa_mask. Dacă indicatorul nu este setat, acest semnal este blocat automat în timpul procesării. |
SA_RESTART | Dacă este definită o funcție de gestionare, un număr de apeluri de sistem care au fost întrerupte de un semnal primit vor fi repornite automat după procesarea semnalului. Dacă indicatorul nu este setat, apelul de sistem va returna o eroare EINTR. |
SA_SIGINFO * | Dacă dispoziția indică interceptarea semnalului, se apelează funcția adresată de câmpul sa_sigaction. Dacă flag-ul nu este setat, este apelat handler-ul sa_handler. |
SA_NOCLDWAIT * | Dacă semnalul specificat de sig este SIGCHLD , copiii nu vor intra în starea zombie la finalizare. Dacă procesul apelează ulterior funcții așteptați (2), așteptați 3(2), waitid(2) sau waitpid(2), executarea lor va fi blocată până când toți descendenții acestui proces își vor finaliza munca. |
SA_NOCLDSTOP * | Dacă semnalul specificat de sig este SIGCHLD , semnalul specificat nu va fi trimis procesului atunci când oricare dintre copiii acestuia se încheie sau se oprește. |
* Aceste steaguri nu sunt definite pentru UNIX BSD.
Pe sistemele UNIX BSD 4.x, structura sigaction arată astfel:
struct sigaction (
void (*sa_handler)();
sigset_t sa_mask;
unde funcția de gestionare este definită după cum urmează:
void handler (int signo, int cod, struct sigcontext *scp);
Primul argument signo conține numărul semnalului, specifică codul Informații suplimentare despre motivul semnalului, iar scp indică contextul procesului.
Pentru UNIX System V, următoarea oportunitate a fost implementată pentru a obține mai multe informatii complete despre semnal. Dacă steag-ul SA_SIGINFO este setat, atunci când este primit un semnal sig, va fi apelat handlerul adresat de câmpul sa_sigaction. În plus față de numărul de semnal transmis în mod obișnuit la manipulatorul de semnal, acesta va fi transmis un pointer către o structură siginfo_t care conține informații despre motivul pentru care a fost primit semnalul, precum și un pointer către o structură ucontext_t care conține contextul procesului.
Structura siginfo_t este definită în fișier
Câmpul si_signo stochează numărul semnalului. Câmpul si_code are următoarea semnificație: dacă valoarea sa este mai mică sau egală cu zero, atunci semnalul a fost trimis de procesul de aplicare, caz în care structura siginfo_t conține și următoarele câmpuri:
care se adresează procesului care a trimis semnalul; dacă valoarea si_code este mai mare decât zero, atunci indică motivul trimiterii semnalului. Listă valori posibile si_code pentru unele semnale corespunzătoare câmpului si_signo este dat în tabel. 2.19
Tabelul 2.19. Valorile câmpului si_code al structurii siginfo_t pentru unele semnale
valoarea câmpului si_signo | valoarea câmpului si_code | Descriere |
---|---|---|
SIGILL | Încercarea de a executa o instrucțiune nevalidă | |
ILL_ILLOPC | Cod operațional nevalid | |
ILL_ILLOPN | Operand nevalid | |
ILL_ADR | Mod de adresare nevalid | |
ILL_ILLTRP | Capcană nevalidă | |
ILL_PRVOPC | Opcode privilegiat | |
ILL_PRVREG | Registrul privilegiat | |
ILL_COPROC | Eroare de coprocesor | |
ILL_BADSTK | Eroare de stivă internă | |
SIGFPE | Situație specială în virgulă mobilă | |
FPE_INTDIV | Împărțirea întregului cu zero | |
FPE_INTOVF | Depășire întreg | |
FPE_FLTDIV | Împărțirea cu virgulă mobilă zero | |
FPE_FLTOVF | Debordare în virgulă flotantă | |
FPE_FLTUND | Pierderea preciziei în virgulă mobilă (subflux) | |
FPE_FLTRES | Rezultat ambiguu al operațiunii în virgulă mobilă | |
FPE_FLTINV | Operatie invalida cu numere cu virgula mobila | |
FPE_FLTSUB | Index în afara intervalului | |
SIGSEGV | Încălcarea segmentării | |
SEGV_MAPPER | Adresa nu este mapată la obiect | |
SEGV_ACCERR | Drepturi insuficiente asupra obiectului afișat | |
SIGBUS | Eroare de adresare | |
BUS_ADRALN | Alinierea adresei nevalidă | |
BUS_ADRERR | Adresă fizică inexistentă | |
BUS_OBJERR | Eroare hardware asociată cu obiectul | |
SIGTRAP | Capcană | |
TRAP_BRKPT | Procesul a atins un punct de întrerupere | |
TRAP_TRACE | Capcană de urmărire a procesului | |
SIGCHLD | Încheierea unui proces copil | |
CLD_EXITED | Procesul copil a finalizat execuția | |
CLD_KILLED | Procesul copilului a fost ucis | |
CLD_DUMPED | Încetarea anormală a procesului copilului | |
CLD_TRAPPED | Procesul copil urmărit este blocat | |
CLD_OPRIT | Execuția procesului copil a fost oprită | |
CLD_CONTINUED | Execuția unui proces copil oprit a fost continuată | |
SIGPOLL | Eveniment pe dispozitivul care este interogat | |
POLL_IN | Datele de intrare au sosit | |
POLL_OUT | Buffere de date gratuite | |
POLL_MSG | Mesaj în așteptare | |
POLL_ERR | Eroare I/O | |
POLL_PRI | Datele cu prioritate ridicată așteaptă introducerea | |
POLL_HUP | Dispozitivul este dezactivat |
S-a remarcat deja că atunci când se primește un semnal de la un proces utilizator, structura siginfo_t conține câmpuri suplimentare (Tabelul 2.20).
Tabelul 2.20. Câmpuri suplimentare ale structurii signinfo_t
Puteți seta o mască de semnal sau puteți obține masca curentă folosind funcția sigprocmask(2):
#include
int sigprocmask(int how, sigset_t *set, sigset_t *oset);
Masca de semnal se modifică în funcție de argumentul how, care poate lua următoarele valori:
Dacă indicatorul setării este NULL, atunci argumentul how este ignorat. Dacă argumentul oset nu este NULL, atunci masca semnalului curent este plasată în setul adresat de acest argument.
Funcţie semnătură (2) folosit pentru a primi un set de semnale blocate care așteaptă livrarea:
#include
int sigpending(int how, sigset_t *set, sigset_t *oset);
Lista semnalelor care așteaptă să fie livrate este returnată în setul adresat de argumentul set.
Apel de sistem sigsuspend(2)înlocuiește masca curentă cu setul adresat de argumentul set și suspendă execuția procesului până când primește semnale a căror dispoziție este setată fie să încheie execuția procesului, fie să apeleze o funcție de gestionare a semnalului.
#include
int sigsuspend(const sigset_t *set);
Când este primit un semnal care încheie procesul, funcția revine sigsuspend(2) nu se intampla. Dacă dispoziția semnalului primit este setată să apeleze funcția de gestionare, întoarceți de la suspendare (2) apare imediat după finalizarea procesării semnalului. În acest caz, masca care exista înainte de apel este restaurată sigsuspend(2).
Rețineți că în BSD UNIX apelul semnal (3) este o interfață simplificată la o funcție mai generală sigatie(2), în timp ce în ramura System V semnal (3) implică utilizarea semanticii vechi a semnalelor nesigure.
În concluzie, pentru a ilustra considerațiile de mai sus, vă prezentăm o versiune a funcției semnal(), permițând utilizarea semnalelor fiabile. O implementare similară este utilizată în BSD UNIX. Cu această versiune „robustă”, vom repeta exemplul discutat mai sus, într-o formă modificată.
#include
#include
#include
#include
#include
/* O variantă a funcției "de încredere" signal() */
void (*mysignal(int signo, void (*hndlr)(int)))(int) (
struct sigaction act, oact;
/* Setați masca de semnal */
act.sa_handler = hndlr;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo != SIGALRM)
act.sa_flags = SA_RESTART;
/* Setați dispoziția */
dacă (sigaction(signo, &act, &oact)< 0)
return(oact.sa_handler);
/* Funcția de gestionare a semnalului */
static void sig_hndlr(int signo) (
/* Nu mai avem nevoie de această parte a codului
mysignal(SIGINT, sig_hndlr);
printf("Semnal SIGINT primit");
/* Setați dispoziția */
mysignal(SIGINT, sig_hndlr);
mysignal(SIGUSR2, SIG_IGN);
/* Ciclu fără sfârșit */
Rețineți că atunci când utilizați semnale de încredere, nu este nevoie să restabiliți dispoziția în funcția de gestionare atunci când semnalul este primit.
Din cartea Arhitectura sistemului de operare UNIX autorul Bach Maurice J7.2 SEMNALE Semnalele notifică procesele că au avut loc evenimente asincrone. Semnalele sunt trimise de procese - unul către altul, folosind funcția kill - sau de nucleu. În versiunea V (a doua ediție) a sistemului UNIX, există 19 diverse semnale, care pot fi clasificate
De pe serverul de carte DIY Linux autor5.8.2. Semnale Daemonul syslogd răspunde la următoarele semnale: SYGTERM, SIGINT, SIGQUIT, SIGHUP, SIGUSR1, SIGCHLD. Reacția demonului la semnale este descrisă în tabel. 5.8 Reacția demonului la semnale Tabelul 5.8 Reacția semnalului SIGTERM Termină demonul SIGINT, SIGQUIT Termină demonul dacă depanarea este dezactivată.
autor Raymond Eric Stephen Din cartea Arta programarii pentru Unix autor Raymond Eric Stephen7.2.6.2. Semnale Cel mai simplu și mai crud mod de a comunica între două procese de pe aceeași mașină este ca unul dintre ele să trimită celuilalt un fel de semnal. Semnalele din sistemul de operare Unix sunt o formă de întrerupere software. Fiecare semnal
Din cartea Infrastructuri chei publice autor Polyanskaya Olga YurievnaSurse de timp sigure Un serviciu de întâlniri securizat necesită una sau mai multe surse de timp sigure, adică o modalitate de a obține o reprezentare fiabilă a orei curente (sincronă cu ora globală, cu nivel inalt precizie) unul sau
Din cartea Dezvoltarea aplicațiilor în Mediul Linux. A doua editie autor Johnson Michael K.12.1.3. Semnale de încredere Implementarea BSD a problemei semnalelor multiple se bazează pe simpla așteptare ca fiecare handler de semnal dintr-un proces să se finalizeze înainte de a furniza următorul. Acest lucru asigură că fiecare semnal va fi procesat mai devreme sau mai târziu și
Din cartea Linux: Ghidul complet autor Kolisnichenko Denis Nikolaevici3.3.2. Semnale Mecanismul de semnalizare este un mijloc care permite proceselor să fie notificate despre anumite evenimente din sistem, iar procesului de recepție să răspundă în mod corespunzător la aceste mesaje. Semnalul poate fi trimis de către procesul în sine (de exemplu, atunci când se încearcă împărțirea la zero) sau de către nucleu (în caz de eșec
Din cartea QNX/UNIX [Anatomy of Concurrency] autor Tsilurik Oleg Ivanovici27.3.10. Semnale și prize Există trei semnale asociate cu prize:? SIGIO - soclul este gata pentru I/O. Semnalul este trimis procesului care este asociat cu priza;? SIGURG - priza a primit date expres (nu le vom folosi, deci nu are rost să ne oprim asupra lor);? SIGPIPE - record
Din cartea Programare pentru Linux. Abordare profesională de Mitchell Mark3. Semnale
Din cartea Sala de operatie sistem UNIX autor Robachevsky Andrey M. Din cartea Linux și UNIX: programare shell. Ghidul dezvoltatorului. de Tainsley David3.3. Semnale Semnalele sunt mecanismul de comunicare între procese în Linux. Acest subiect este foarte larg, așa că aici vom lua în considerare doar cele mai importante semnale și tehnici de control al procesului mesaj special, trimis la proces. Semnalele sunt
Din cartea Learning Explosion: Nine Rules for a Effective Virtual Classroom de Murdoch MatthewSemnale Semnalele sunt o modalitate de transmitere a notificărilor de la un proces la altul sau de la nucleul sistemului de operare către un proces că un anumit eveniment a avut loc. Semnalele pot fi privite ca cea mai simpla forma comunicarea intraprocesuala. La acelasi
Din cartea autorului Din cartea autoruluiSemnale Într-un sens, semnalele oferă cea mai simplă formă de comunicare între procese, permițând unui proces sau unui grup de procese să fie notificat despre apariția unui eveniment. Am analizat deja semnalele din punctul de vedere al utilizatorului și
Din cartea autorului26.2. Semnale Un semnal se referă la un tip de mesaj care este trimis de la un sistem pentru a informa o comandă sau un script că a avut loc un eveniment. De obicei despre care vorbim erori de memorie, probleme de accesare a informațiilor sau
IPC, comunicare între procese ). De fapt, un semnal este o notificare asincronă a unui proces despre un anumit eveniment. Când un semnal este trimis unui proces, sistemul de operare întrerupe execuția procesului. Dacă un proces și-a instalat propriul său proces manipulator de semnal, sistemul de operare pornește acest handler prin transmiterea informațiilor despre semnal. Dacă procesul nu a instalat un handler, este executat handler-ul implicit.Numele semnalelor "SIG..." sunt constante numerice (definiții macro C) cu valori definite în fișier antet semnal.h . Valorile numerice ale semnalelor pot varia de la sistem la sistem, deși cea mai mare parte a acestora are sisteme diferite aceleasi valori. Utilitarul kill vă permite să specificați un semnal fie ca număr, fie ca simbol.
Trimiterea semnalelor
Semnalele sunt trimise:
- din terminal apăsând chei speciale sau combinații (de exemplu, apăsarea Ctrl-C generează SIGINT , Ctrl-\ SIGQUIT și Ctrl-Z SIGTSTP );
- miezul sistemului:
- când apar excepții hardware (instrucțiuni nevalide, încălcări de acces la memorie, defecțiuni ale sistemului etc.);
- apeluri de sistem eronate;
- pentru a raporta evenimente I/O;
- un proces la altul (sau la sine), folosind apelul de sistem kill(), inclusiv:
Semnalele nu pot fi trimise către un proces terminat care este în stare zombie.
Procesare a semnalului
Managerul implicit pentru majoritatea semnalelor încheie procesul. Pentru a gestiona alternativ toate semnalele, cu excepția SIGKILL și SIGSTOP, un proces își poate atribui propriul handler sau poate ignora apariția acestora modificându-și masca de semnalizare. Singura excepție este procesul cu pid 1 (init), care are dreptul de a ignora sau procesa orice semnal, inclusiv KILL și STOP.
Siguranță
Un proces (sau utilizator shell) cu un UID efectiv altul decât 0 (UID-ul de superutilizator) poate trimite semnale numai proceselor cu același UID.
Clasificarea semnalelor
POSIX definește 28 de semnale, care pot fi clasificate după cum urmează:
Nume | Cod | Acțiune implicită | Descriere | Tip |
---|---|---|---|---|
SIGABRT | 6 | Se completează cu un dump de memorie | Semnal trimis de funcția abort(). | Control |
SIGALRM | 14 | Completare | Semnalează când timpul specificat de alarm() a expirat | Notificare |
SIGBUS | 10 | Se completează cu un dump de memorie | Acces incorect la memoria fizică | Excepție |
SIGCHLD | 18 | Ignorat | Procesul copil a fost încheiat sau oprit | Notificare |
SIGCONT | 25 | Continuați execuția | Continuați execuția unui proces oprit anterior | Control |
SIGFPE | 8 | Se completează cu un dump de memorie | Operație aritmetică eronată | Excepție |
SUPRAȚI | 1 | Completare | Închiderea terminalului | Notificare |
SIGILL | 4 | Se completează cu un dump de memorie | Instrucțiune nevalidă pentru procesor | Excepție |
SIGINT | 2 | Completare | Semnal de întrerupere (Ctrl-C) de la terminal | Control |
SIGKILL | 9 | Completare | Finalizare necondiționată | Control |
SIGPIPE | 13 | Completare | Scrierea la o conexiune întreruptă (țeavă, priză) | Notificare |
SIGQUIT | 3 | Se completează cu un dump de memorie | Semnal „Ieșire” de la terminal (Ctrl-\) | Control |
SIGSEGV | 11 | Se completează cu un dump de memorie | Recuperarea memoriei afectată | Excepție |
SIGSTOP | 23 | Oprirea procesului | Oprirea unui proces | Control |
SIGTERM | 15 | Completare | Semnal de terminare (semnal implicit pentru utilitarul kill) | Control |
SIGTSTP | 20 | Oprirea procesului | Semnal de oprire de la terminal (Ctrl-Z). | Control |
SIGTTIN | 26 | Oprirea procesului | Încercați să citiți de pe terminal prin proces de fundal | Control |
SIGTTOU | 27 | Oprirea procesului | O încercare de a scrie pe terminal printr-un proces de fundal | Control |
SIGUSR1 | 16 | Completare | Semnal utilizator #1 | Personalizat |
SIGUSR2 | 17 | Completare | Semnal utilizator #2 | Personalizat |
SIGPOLL | 22 | Completare | Eveniment monitorizat de sondaj() | Notificare |
SIGPROF | 29 | Completare | Cronometrul de profilare a expirat | Depanare |
SIGSYS | 12 | Se completează cu un dump de memorie | Apel de sistem incorect | Excepție |
SIGTRAP | 5 | Se completează cu un dump de memorie | Urmărirea capcanei sau a punctului de întrerupere | Depanare |
SIGURG | 21 | Ignorat | Date urgente primite pe socket | Notificare |
SIGVTALRM | 28 | Completare | Expirarea „temporizatorului virtual” | Notificare |
SIGXCPU | 30 | Se completează cu un dump de memorie | Procesul a depășit limita de timp CPU | Excepție |
SIGXFSZ | 31 | Se completează cu un dump de memorie | Procesul a depășit dimensiunea permisă a fișierului | Excepție |
Când gestionează excepții și semnale de depanare, un proces poate scrie un fișier de descărcare a memoriei procesului în directorul curent înainte de a ieși. imagine de bază), folosind care depanatorul poate reconstrui condițiile în care s-a produs această excepție. Uneori (de exemplu, pentru programele executate ca superutilizator) un dump de memorie nu este creat din motive de securitate.
SA_SIGINFO
De obicei, un handler de semnal primește un singur argument - numărul semnalului (acest lucru vă permite să utilizați o funcție de handler pentru mai multe semnale). Dacă, atunci când specificați un handler de semnal (folosind funcția sigaction()), specificați opțiunea SA_SIGINFO, atunci încă două argumente vor fi transmise handlerului:
- pointer către o structură siginfo_t care conține:
- o mască de bit de „coduri de semnal” suplimentare care determină cauza apariției acesteia;
- identificatorul de proces (PID) care a trimis semnalul;
- identificatorul efectiv de utilizator (UID) sub care rulează procesul (de exemplu, utilitarul kill) care a trimis semnalul;
- adresa instrucțiunii în care s-a produs excepția;
- și așa mai departe.
- un pointer către „contextul mașinii” în momentul în care a apărut semnalul (cu o „stivă de semnale” - date suplimentare care sunt împinse în stivă atunci când anumite semnale de excepție sunt ridicate).
Majoritatea codurilor suplimentare sunt specifice fiecărui semnal. Coduri comune tuturor semnalelor:
Vezi si
Scrieți o recenzie despre articolul „Semnale (UNIX)”
Legături
- - Conceptul de semnal (IEEE Std 1003.1, ediția 2004)
- - Descrierea structurilor și constantelor asociate cu semnalele (IEEE Std 1003.1, 2004 Edition)
- - „Reguli de utilizare a semnalelor în Unix” (Mesaj în conferința RU.UNIX.PROG)
Extras care descrie semnalele (UNIX)
„Îți voi cânta toată seara”, a spus Natasha.- Vrăjitoarea îmi va face orice! – spuse Denisov și și-a desfăcut sabia. A ieșit din spatele scaunelor, și-a luat cu fermitate doamna de mână, și-a ridicat capul și a lăsat piciorul în jos, așteptând tact. Doar călare și în mazurcă, statura mică a lui Denisov nu era vizibilă și părea să fie același tânăr pe care îl simțea el însuși. După ce a așteptat ritmul, a aruncat o privire triumfătoare și jucăușă către doamna lui din lateral, a bătut brusc cu un picior și, ca o minge, a sărit elastic de pe podea și a zburat în cerc, târându-și doamna cu el. A zburat în tăcere la jumătatea holului pe un picior și i se părea că nu vedea scaunele stând în fața lui și se repezi direct spre ele; dar deodată, bătând din pinteni și desfăcându-și picioarele, s-a oprit pe călcâie, a rămas acolo o secundă, cu vuiet de pinteni, și-a bătut picioarele într-un loc, s-a întors repede și, ciocănindu-și piciorul drept cu piciorul stâng, a zburat din nou în cerc. Natasha a ghicit ce intenționa să facă și, fără să știe cum, l-a urmat - predându-se lui. Acum o înconjura, când pe dreapta, când pe mâna stângă, când căzând în genunchi, a înconjurat-o în jurul său și din nou a sărit în sus și a alergat înainte cu atâta viteză, de parcă ar fi vrut să alerge prin toate camerele. fără a respira; apoi deodată s-a oprit iar și iar și a făcut un genunchi nou și neașteptat. Când el, învârtind-o cu viteză pe doamna în fața ei, și-a rupt pintenul, făcându-și o plecăciune în fața ei, Natasha nici măcar nu i-a făcut o reverență. Se uită la el uluită, zâmbind de parcă nu l-ar fi recunoscut. - Ce este asta? - ea a spus.
În ciuda faptului că Yogel nu a recunoscut această mazurcă ca fiind reală, toată lumea a fost încântată de priceperea lui Denisov, au început să-l aleagă neîncetat, iar bătrânii, zâmbind, au început să vorbească despre Polonia și vremurile bune. Denisov, îmbujorat de mazurcă și ștergându-se cu o batistă, s-a așezat lângă Natasha și nu a părăsit-o pe tot parcursul mingii.
Două zile după aceasta, Rostov nu l-a văzut pe Dolokhov cu oamenii săi și nu l-a găsit acasă; a treia zi a primit un bilet de la el. „Din moment ce nu mai intenționez să vă vizitez casa din motive cunoscute de dvs. și mă duc la armată, în această seară le dau prietenilor mei o petrecere de rămas bun - vino la hotelul englezesc.” Rostov la ora 10, de la teatru, unde se afla cu familia și Denisov, a ajuns în ziua stabilită la hotelul englezesc. A fost dus imediat în cea mai bună cameră a hotelului, ocupată pentru acea noapte de Dolokhov. În jurul mesei se înghesuiau vreo douăzeci de oameni, în fața căreia Dolokhov stătea între două lumânări. Pe masă era aur și bancnote, iar Dolokhov arunca o bancă. După propunerea și refuzul Soniei, Nikolai nu-l văzuse încă și era confuz la gândul cum se vor întâlni.
Privirea luminoasă și rece a lui Dolokhov l-a întâlnit pe Rostov la ușă, de parcă l-ar fi așteptat de mult.
„De mult timp fără să ne vedem”, a spus el, „mulțumesc că ai venit”. Voi ajunge acasă și Ilyushka va apărea cu corul.
— Am venit să te văd, spuse Rostov roșind.
Dolokhov nu i-a răspuns. „Poți paria”, a spus el.
Rostov și-a amintit în acel moment de o conversație ciudată pe care a avut-o cândva cu Dolokhov. „Numai proștii pot juca pentru noroc”, a spus atunci Dolokhov.
– Sau ți-e frică să te joci cu mine? - spuse acum Dolokhov, de parcă ar fi ghicit gândul lui Rostov, și a zâmbit. Din cauza zâmbetului său, Rostov a văzut în el starea de spirit pe care o avea în timpul cinei la club și, în general, în acele momente în care, parcă plictisit de viața de zi cu zi, Dolokhov simțea nevoia să iasă din ea într-un fel ciudat, mai ales. crud, act.
Rostov se simțea stânjenit; a căutat și nu a găsit în mintea lui o glumă care să răspundă cuvintelor lui Dolokhov. Dar înainte de a putea face asta, Dolokhov, privindu-l drept în fața lui Rostov, încet și deliberat, pentru ca toată lumea să poată auzi, i-a spus:
– Îți amintești că am vorbit despre joc... un prost care vrea să joace de noroc; Probabil ar trebui să joc, dar vreau să încerc.
— Încearcă să ai noroc, sau poate? gândi Rostov.
„Și e mai bine să nu te joci”, a adăugat el și, rupând pachetul rupt, a adăugat: „Bancă, domnilor!”
Mutând banii înainte, Dolokhov s-a pregătit să arunce. Rostov s-a așezat lângă el și nu a jucat la început. Dolokhov îi aruncă o privire.
- De ce nu te joci? – spuse Dolokhov. Și în mod ciudat, Nikolai a simțit nevoia să ia o carte, să pună un mic jackpot și să înceapă jocul.
„Nu am bani la mine”, a spus Rostov.
- O sa cred!
Rostov a pariat 5 ruble pe carte și a pierdut, a mai pariat și a pierdut din nou. Dolokhov a ucis, adică a câștigat zece cărți la rând de la Rostov.
„Domnilor”, a spus el, după ce a petrecut ceva timp, „vă rog să puneți bani pe carduri, altfel s-ar putea să mă încurc în conturi”.
Un jucător a spus că speră să aibă încredere în el.
– Îmi vine să cred, dar mi-e frică să nu mă încurc; „Vă rog să puneți bani pe carduri”, a răspuns Dolokhov. „Nu fi timid, ne vom descurca cu tine”, a adăugat el lui Rostov.
Jocul a continuat: lacheul, fără încetare, a servit șampanie.
Toate cărțile lui Rostov au fost sparte și pe el au fost scrise până la 800 de tone de ruble. A scris 800 de mii de ruble pe o singură carte, dar în timp ce i se servea șampanie, s-a răzgândit și a scris din nou suma obișnuită, douăzeci de ruble.
„Lăsați”, a spus Dolokhov, deși nu părea să se uite la Rostov, „veți primi și mai devreme”. Dau altora, dar te bat. Sau ți-e frică de mine? – repetă el.
Rostov a ascultat, a lăsat scrisul 800 și a așezat cele șapte inimi cu un colț rupt, pe care le-a ridicat de la pământ. Și-a amintit bine de ea după aceea. El a pus cele șapte inimi, scriind deasupra lui 800 cu o bucată de cretă ruptă, în numere rotunde, drepte; a băut paharul de șampanie încălzită servit, a zâmbit la cuvintele lui Dolokhov și, cu răsuflarea tăiată, așteptând pe cei șapte, a început să se uite la mâinile lui Dolokhov care țineau puntea. A câștiga sau a pierde acest șapte de inimi a însemnat mult pentru Rostov. Duminică, săptămâna trecută, contele Ilya Andreich i-a dat fiului său 2.000 de ruble, iar acestuia, căruia nu i-a plăcut niciodată să vorbească despre dificultăți financiare, i-a spus că acești bani sunt ultimii până în mai și de aceea i-a cerut fiului său să fie mai economic. de data asta. Nikolai a spus că asta era prea mult pentru el și că și-a dat cuvântul de onoare să nu mai ia bani până în primăvară. Acum au mai rămas 1.200 de ruble din acești bani. Prin urmare, cele șapte inimi au însemnat nu numai o pierdere de 1.600 de ruble, ci și nevoia de schimbare acest cuvânt. Cu inima scufundată, s-a uitat la mâinile lui Dolokhov și s-a gândit: „Ei bine, repede, dă-mi acest card și îmi iau șapca, mă duc acasă la cină cu Denisov, Natasha și Sonya și cu siguranță nu voi avea niciodată un card în mâinile mele.” În acest moment Viata acasa glumele lui cu Petya, conversațiile cu Sonya, duetele cu Natasha, un pichet cu tatăl său și chiar un pat calm în casa bucătarului, i s-au prezentat cu atâta putere, claritate și farmec, de parcă toate acestea ar fi trecut de mult, pierdute. și fericire neapreciată. Nu putea permite ca un accident stupid, forțându-i pe cei șapte să se întindă mai întâi pe dreapta decât pe stânga, să-l priveze de toată această fericire nou înțeleasă, nou luminată și să-l cufunde în abisul unei nenorociri încă netestate și incerte. Nu se putea, dar totuși aștepta cu răsuflarea tăiată mișcarea mâinilor lui Dolokhov. Aceste mâini cu oase late, roșiatice, cu părul vizibil de sub cămașă, au pus jos un pachet de cărți și au apucat paharul și pipa care erau servite.
Seria de conținut:
În sistemele de operare moderne, există conceptul de comunicare între procese (IPC) - acesta este un set de metode pentru schimbul de date între procese și/sau fire. Una dintre aceste metode de schimb este semnalele. Conceptul de semnale este acceptat de majoritatea sistemelor de operare, dar, de exemplu, Windows nu are suport complet pentru utilizarea lor ca una dintre metodele IPC - în astfel de sisteme de operare semnalele sunt implementate doar în bibliotecă standard limbajul C
Conceptul de semnal
Semnalele sunt capabile să întrerupă un proces în momente aleatorii (asincron) pentru a procesa un eveniment. Un proces poate fi întrerupt de un semnal inițiat de un alt proces sau nucleu. Nucleul folosește semnale pentru a notifica procesele despre diverse evenimente, cum ar fi moartea unui proces copil.
Semnalele au un anumit ciclu de viață. În primul rând, semnalul este creat - trimis de proces sau generat de nucleu. Semnalul așteaptă apoi să fie livrat procesului de recepție. Este în general acceptat că perioada de așteptare pentru un semnal este egală cu intervalul de timp dintre crearea semnalului și acțiunea pe care o trimite acest semnal. La sfârșitul ciclului de viață al semnalului, acesta este interceptat (primit) de către proces și sunt efectuate acțiuni legate de semnal.
Semnale simple și semnale fiabile
Există o împărțire a semnalelor în simple și fiabile.
Inițial, au fost dezvoltate și utilizate semnale simple (nesigure). În principiul lor de funcționare, ele sunt similare cu mecanismul canonic de procesare a întreruperilor hardware în procesor. Dacă un proces dorește să proceseze un anumit semnal într-un mod special, atunci informează nucleul despre acest lucru prin specificarea unei funcții speciale - un handler de semnal. Când un semnal este livrat unui proces, nucleul invocă un handler de semnal cât mai curând posibil, întrerupând procesul. Când handler-ul își finalizează execuția, procesul continuă de unde a fost întrerupt.
În loc să scrieți propria funcție de gestionare, puteți spune pur și simplu nucleului că semnalul provoacă acțiunea implicită sau că semnalul este pur și simplu ignorat.
Tot acest concept de lucru cu semnale sună destul de bine până când un semnal ajunge la un proces în timp ce acesta este deja ocupat cu procesarea unui alt semnal. Aici apar problemele - un handler de semnal numit în mod repetat poate corupa acele resurse partajate ( structuri generale date și variabile) pe care le folosește. În plus, dacă sosesc un număr mare de semnale, stiva de proces poate crește nelimitat, ceea ce poate duce la eșecuri ale programului.
În procesul de rezolvare a problemei, au fost dezvoltate semnale fiabile, care au fost standardizate în POSIX și sunt încă folosite astăzi. În continuare, în articol, sunt discutate semnale fiabile.
Semnale și apeluri de sistem
Semnalul poate ajunge la proces în timp ce procesul este în interiorul unui apel de sistem, de exemplu, așteaptă intrarea pentru a citi(). În acest caz, desfășurarea evenimentelor poate urma următoarea cale: aplicația nu încearcă să intercepteze semnalul și este întreruptă de nucleu (de exemplu, sosirea semnalului SIGTERM) - atunci terminalul rămâne într-un non-standard. configurație, ceea ce poate complica munca utilizatorului. Desigur, puteți intercepta semnalul, ștergeți terminalul din handlerul de semnal și apoi ieșiți, dar este destul de dificil să scrieți un handler de semnal care știe ce făcea programul în momentul întreruperii pentru a decide dacă să ștergeți terminalul sau nu.
Astăzi există o implementare a semnalelor care este liberă de aceste neajunsuri. Soluția este să setați pur și simplu un steag în handlerul de semnal pentru a indica faptul că semnalul a fost primit și apoi să vă asigurați că apelul de sistem revine cu un cod de eroare care indică faptul că apelul a fost întrerupt de semnal. În continuare, programul trebuie să verifice steag-ul setat de manipulatorul de semnal și să ia măsurile corespunzătoare, cum ar fi ștergerea terminalului și ieșirea.
Implementările moderne de semnal determină apelurile lente de sistem pentru a returna codul de eroare EINTR atunci când sunt întrerupte de un semnal de intrare. Apelurile rapide de sistem trebuie să se finalizeze înainte ca semnalul să fie livrat. Un apel de sistem lent este un apel de sistem care durează o perioadă nedeterminată de timp pentru a se finaliza, cum ar fi read(), wait(), write(). Toate apelurile de sistem care depind de resurse imprevizibile, cum ar fi acțiunile umane, datele din rețea etc., sunt lente. Desigur, toate celelalte apeluri de sistem sunt rapide.
De obicei, programul va gestiona codul de eroare EINTR și, dacă nu s-a întâmplat nimic fatal, repornește apelul de sistem. Majoritatea sistemelor de operare asemănătoare Unix fac acum acest lucru în mod implicit - trebuie doar să gestionați semnalul într-un handler, iar apelul de sistem va fi repornit automat. În Linux, apelurile de sistem nu sunt repornite în mod implicit, dar pentru fiecare semnal un proces poate seta un indicator pentru a spune sistemului să repornească apelurile lente de sistem întrerupte de acel semnal.
Trimiterea semnalelor
Trimiterea semnalelor de la un proces la altul se face de obicei folosind apelul de sistem kill(). Primul său parametru este PID-ul procesului către care este trimis semnalul; al doilea parametru este numărul semnalului. Dacă vrem să trimitem un semnal SIGTERM unui proces cu PID 6666, folosim apelul de sistem kill() astfel:
kill(6666, SIGTERM);În loc de o valoare PID pozitivă, puteți transmite apelului o valoare egală, dar negativă. Apoi semnalul va fi trimis tuturor proceselor din grupul cu un număr egal cu modulul PID-ului trecut. Dacă PID-ul este 0, atunci semnalul este trimis tuturor proceselor din grupul căruia îi aparține procesul curent sunt utilizate în principal de shell-uri pentru gestionarea locurilor de muncă.
Dacă treceți valoarea -1 ca PID apelului de sistem kill(), semnalul va fi trimis către toate procesele, cu excepția init. Această caracteristică este utilizată pentru a opri sistemul.
Pentru mai multe informații despre apelul de sistem kill(), vezi man 2 kill.
Un proces poate trimite un semnal către el însuși folosind apelul de sistem raise(), care ia un parametru - numărul semnalului. Exemplu:
ridicare(SIGTERM);Desigur, fiecare dintre apelurile de sistem discutate mai sus returnează zero dacă are succes și o valoare diferită de zero dacă apare o eroare.
Interceptarea semnalului
Toate programele POSIX își înregistrează gestionatorii de semnal folosind apelul de sistem sigaction(). Acest apel de sistem are trei parametri: primul – int signum – numărul semnalului interceptat. Al doilea este struct sigaction * act – un pointer către o structură care descrie regulile de instalare a handler-ului. Al treilea parametru – struct sigaction * oact – ia deja regulile stabilite manipulator de semnal. Al doilea sau al treilea parametru (dar nu ambii!) poate fi setat la NULL dacă este necesar.
Structura struct sigaction are următoarea descriere:
struct sigaction ( __sighandler_t sa_handler; sigset_t sa_mask; int sa_flags; );sa_handler este un pointer către handlerul de semnal, iar handlerul trebuie declarat după cum urmează:
void signal_handler(int signo);unde singurul parametru este numărul semnalului care a fost inclus în handler. sa_handler poate fi, de asemenea, egal cu SIG_IGN - semnalul este ignorat de proces și SIG_DFL - semnalul provoacă o acțiune implicită, cum ar fi întreruperea procesului.
sa_mask – un set de semnale care ar trebui blocat atunci când este apelat handlerul de semnal specificat în aceeași structură. Cum să le instalați este discutat mai jos.
Parametrul sa_flags permite unui proces să modifice comportamentul semnalului. Parametrul poate lua doar patru valori, care, totuși, pot fi combinate folosind operația de biți „OR”:
- SA_NOCLDSTOP – Trimite semnalul SIGCHLD numai dacă procesul copil este întrerupt. Suspendarea unui proces copil nu determină trimiterea unui semnal.
- SA_NODEFER – emularea semnalelor simple (nesigure).
- SA_RESTHAND – după ce sosește un semnal, handlerul acestuia este resetat la SIG_DFL.
- SA_RESTART – reporniți apelul de sistem după revenirea de la manipulatorul de semnal. Dacă indicatorul nu este setat, apelul de sistem returnează eroarea EINTR.
Ca de obicei, sigaction() returnează 0 la succes și o valoare negativă la eroare.
Mască semnal de proces
Adăugarea de semnale la structura sigset_t sa_mask, ștergerea acesteia etc. sunt efectuate folosind un set de funcții sigemptyset(), sigfillset(), sigaddset(), sigdelset(). Primele două funcții iau un parametru – un pointer către structura sigset_t. Aceste funcții șterg și umplu structura sigset_t cu toate semnalele posibile, respectiv.
Ultimele două funcții, respectiv, adaugă și elimină un semnal specific din structură și au câte doi parametri fiecare. Primul lor parametru este un pointer către structura sigset_t, iar al doilea este numărul semnalului.
Toate funcțiile discutate mai sus returnează 0 la succes și un număr diferit de zero la eroare.
În plus, există o altă funcție care verifică dacă semnalul specificat se află în setul specificat - sigismember(). Parametrii săi sunt aceiași cu cei ai sigaddset(). Funcția returnează 1 dacă semnalul este în set, 0 dacă nu este și un număr negativ dacă a apărut o eroare.
Printre altele, putem specifica o listă de semnale a căror livrare către proces va fi blocată. Acest lucru se face folosind funcția sigprocmask(int how, const sigset_t * set, sigset_t * oldset).
Primul său parametru descrie ce trebuie efectuat:
- SIG_BLOCK – semnalele din set sunt blocate;
- SIG_UNBLOCK – semnalele din set sunt deblocate;
- SIG_SETMASK – semnalele din set sunt blocate, restul sunt deblocate.
Al doilea parametru este un pointer către setul de la care semnalele sunt blocate/deblocate. Dacă este NULL, atunci valoarea primului parametru este ignorată de apelul de sistem.
Al treilea parametru este un pointer către o mască de semnal deja utilizată; poate fi setat la NULL dacă aceste date nu sunt necesare.
Pentru a obține o listă de semnale în așteptare, puteți utiliza funcția sigpending(), care ia un singur parametru - un pointer către structura sigset_t, unde va fi scris setul de semnale în așteptare.
Principii de scriere a manipulatorilor de semnal
Una dintre cele mai importante reguli pentru scrierea manipulatorilor de semnal este că manipulatorul trebuie să fie reintrat, adică. trebuie să permită apelarea din nou atunci când procesul este deja într-un handler. Trebuie avut grijă ca manipulatorul de semnal să nu folosească structuri globale date sau apeluri lente de sistem. Dacă, din păcate, este imposibil să evitați acest lucru, atunci ar trebui să aveți grijă să vă protejați împotriva apelurilor repetate ale handler-ului în timp ce lucrați cu o structură de date sau cu un apel de sistem. Acest lucru poate fi realizat prin blocarea temporară a livrării semnalului al cărui handler rulează în prezent folosind apelul de sistem sigprocmask(). De exemplu, avem un handler de semnal SIGCHLD și blocăm în el astfel:
void chld_handler(int signum) ( sigset_t set; if (sigemptyset(&set)) ( return;) if (sigaddset(&set, SIGCHLD)) ( return; ) if (sigprocmask(SIG_BLOCK, &set, NULL)) ( return; ) / * face ceva important aici */ if (sigprocmask(SIG_UNBLOCK, &set, NULL)) ( return; ) return;În plus față de tot ceea ce este enumerat mai sus, se crede că handlerul ar trebui să fie cât mai simplu posibil - în mod ideal, ar trebui să seteze un anumit steag și să se încheie, iar restul ar trebui să fie efectuat de partea principală a programului.
Concluzie
Materialul oferit este de bază pentru înțelegerea conceptului de semnale. În principiu, ar trebui să fie suficient să începeți să utilizați semnale în programele dvs.
Seria se va încheia cu o privire la modul în care să primiți (și să trimiteți) date suplimentare de semnal dacă nu aveți suficiente informatii obisnuite că un semnal a venit în procesul tău de undeva.
Resurse pentru descărcare
static.content.url=http://www.site/developerworks/js/artating/
ID articol=495997
ArticleTitle=Lucrul cu semnale în Linux: Partea 1. Bazele lucrului cu semnale