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 Fișier antet sistem. Ele sunt de obicei prescurtate fără prefixul SIG; de exemplu SIGHUP este adesea denumit pur și simplu HUP.

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 și include următoarele câmpuri:

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 J

7.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 autor

5.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 Stephen

7.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 Yurievna

Surse 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 Nikolaevici

3.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 Ivanovici

27.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 Mark

3. Semnale

Din cartea Sala de operatie sistem UNIX autor Robachevsky Andrey M.

Din cartea Linux și UNIX: programare shell. Ghidul dezvoltatorului. de Tainsley David

3.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 Matthew

Semnale 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 autorului

Semnale Î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 autorului

26.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:

  1. 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.
  2. 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”:

  1. SA_NOCLDSTOP – Trimite semnalul SIGCHLD numai dacă procesul copil este întrerupt. Suspendarea unui proces copil nu determină trimiterea unui semnal.
  2. SA_NODEFER – emularea semnalelor simple (nesigure).
  3. SA_RESTHAND – după ce sosește un semnal, handlerul acestuia este resetat la SIG_DFL.
  4. 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:

  1. SIG_BLOCK – semnalele din set sunt blocate;
  2. SIG_UNBLOCK – semnalele din set sunt deblocate;
  3. 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