Semnale Linux

Semnalele reprezintă cel mai simplu mecanism de comunicare între procese pus la dispoziţie de UNIX. Un semnal reprezintă o notificare pe care un proces poate sa o primească de la nucleul sistemului de operare pentru a-l atenţiona că un anumit eveniment s-a produs.

Semnalele sunt codificate prin numere întregi pozitive ele având de asemenea un nume simbolic asociat. Definiţia semnalelor suportate se găseşte în librăria signal.h.

Semnalele pot fi privite ca nişte întreruperi software. În momentul în care un proces recepţionează un semnal acesta poate să îşi întrerupă funcţionarea normală şi să sară la o rutina (funcţie) de tratare a semnalului. După execuţia rutinei de tratare a semnalului, se revine la execuţia instrucţiunii de unde programul a fost întrerupt în momentul apariţiei semnalului.

Nucleul sistemului de operare poate transmite semnale către un proces, dar de asemenea şi un proces poate transmite un semnal către un alt proces. Procesul receptor nu cunoaşte sursa semnalului (cel care a trimis semnalul), ci doar valoarea semnalului (ce semnal a recepţionat).

Transmiterea unui semnal catre un proces

Un semnal poate fi trimis către un proces fie din linia de comandă (shell), fie dintr-un alt proces prin apelarea unei funcţii de sistem.

Ce-a mai folosită comandă pentru transmitere de semnale din shell este comanda kill. Comanda kill primeşte doi parametri: numele sau numărul semnalului ce se doreşte a fi trimis si id-ul procesului către care se doreşte trimiterea mesajului.

    kill –signal pid

Dacă nu este specificat nici un semnal atunci în mod implicit funcţia kill transmite semnalul SIGTERM către proces, ceea ce determină terminarea procesului.

Dacă se doreşte transmiterea unui semnal dintr-o aplicaţie C către alt proces atunci se foloseşte funcţia de sistem kill:

</code> #include <sys/types.h> #include <signal.h> … pid_t my_pid = getpid(); kill(my_pid, SIGTERM); </code>

In exemplul anterior un proces îşi transmite lui însuşi un semnal de terminare, care determină oprirea procesului.

Observaţie: Un proces care a recepţionat un semnal nu cunoaşte sursa acestuia. Nu cunoaşte procesul care a iniţiat operaţia de transmitere a semnalului.

Alte funcţii utile sunt:

  • raise() care este folosită pentru ca un proces să îşi transmită lui însuşi un semnal.
  • pause() care blochează un proces în aşteptarea unui semnal.
  • alarm(sec) determină generarea şi transmiterea către procesul apelant al funcţiei alarm a unui semnal SIGALRM după expirarea timpului dat ca şi argument al funcţiei.

Receptionarea si tratarea semnalelor

Pentru ca un proces să poată să trateze un semnal, acesta trebuie să asocieze la semnalul ce se doreşte a fi tratat o funcţie de tratare a respectivului semnal. Pentru aceasta se foloseşte funcţia de sistem signal.

    #include <stdio.h>     
    #include <unistd.h>  
    #include <signal.h>   
 
    /* functie de tratare semnal */
    void catch_int(int sig_num)
    {
        //signal(SIGINT, catch_int);
        printf("Don't do that\n");
        fflush(stdout);
    }
 
    int main(int argc, char* argv[])
    {
        /* seteaza functie de tratare a semnalului SIGINTINT (Ctrl-C) */
        signal(SIGINT, catch_int);
 
        /* bucla infinita */
        for ( ;; )
            pause();
    }

    

În exemplul anterior se construieşte o aplicaţie care ataşează o funcţie de tratare pentru semnalul INT. Acest semnal poate fi generat, transmis către un proces în momentul în care utilizatorul apasă tasta Ctrl-C. Procesul captează acest mesaj şi afişează un mesaj pe ecran.

În condiţiile în care se doreşte folosirea unor semnale pentru comunicare între procese (transmiterea unor semnalizări de producere de evenimente), programatorul are la dispoziţie două semnale utilizator ce pot fi folosite în acest scop. Aceste semnale sunt SIGUSR1 şi SIGUSR2.