Cloud with rain
.:G
G:.
0 and 1 serie, black on white
pulled card
myjsp.feelinglinux.com
ver. 1.1.9-4
Hallo, welcome to my world.
Here you can find some stuff about computer science.
<<< Enjoy your visit! >>>
0 and 1 serie, white on black

I segnali in C

        Scritto: Giansante Gabriele, 2001     

Per descrivere i segnali, si rende necessario introdurre il concetto di evento.

Un evento, in pratica, e' un fatto accaduto all'interno del sistema. Puo' essere generato dalle periferiche (interrupt, operazioni di I/O), da processi (fra cui quelli di sistema), ecc.
Gli avvenimenti indicati con un evento possono essere vari, completamento di un'operazione i I/O, richiesta di chiusura di un processo, scadenza di periodi di tempo (allarme), ecc.

La generazione di un evento asincrono (cioe' che puo' arrivare in qualsiasi momento) puo' avvenire tramite un segnale rivolto ad un processo.
Quindi, con un segnale, viene indicato il verificarsi di un evento asincrono, oppure la necessita' di compiere una determinata azione associata al segnale stesso. Vengono considerati eventi asincroni perche', il processo destinatario del segnale, lo puo' ricevere solo quando riprende la propria esecuzione (passaggio dello stato di esecuzione da modo kernel a modo utente).

Un segnale puo' essere inviato da un processo ad un altro processo, dal kernel ad un processo oppure da un processo a se' stesso (funzione "alarm"). In ogni caso, l'invio del segnale passa per il kernel. Infatti, il processo non riceve subito il segnale. Se il processo si trova in modalita' utente (esecuzione), il kernel lo "passa" subito. Se, invece, il processo si trova in modo kernel (in attesa di essere scelto per l'esecuzione da pare dello scheduler dei processi), gli  viene "passato" al momento della riattivazione da parte dello scheduler.

Vediamo adesso come si puo' inviare e catturare un segnale.
L'header C contenente le funzioni relative alla gestione dei segnali e' "/usr/include/signal.h".
Il segnale voluto puo' essere mandato con le funzioni "alarm" e "kill" ("kill" non invia necessariamente un segnale di "uccisione"), mentre puo' essere catturato per mezzo della funzione "signal".

Alarm

Come gia' accennato, la funzione "alarm" si usa per far inviare un segnale al processo che la invoca. Piu' precisamente, "alarm" permette l'invio del segnale "SIGALRM" dopo un certo tempo t (specificato come parametro).
Un esempio:

#include <signal.h>
...
unsigned t; //tempo che deve passare
...
//A partire da questo momento, il processo
//ricevera' un segnale di allarme dopo t secondi.
alarm(t);
...
Nel frammento di codice mostrato potrebbe mancare una cosa: il processo deve essere in grado di catturare il segnale per poter avviare una routine utente (catcher). Questa routine puo' essere attivata tramite la funzione "signal" che modifica il comportamento di default del segnale.
La funzione "signal" verra' descritta piu' avanti.
Un'ultima nota riguardante "alarm": usando il valore 0 come tempo, si ottiene l'azzeramento del conteggio eventualmente gia' avviato.

Kill

"Kill" si occupa di inviare un segnale ad un processo di cui si conosca il PID (Process IDentification number), o ad un gruppo di processi con lo stesso PGID (Progress Group IDentification number).
Abbiamo visto che e' comunque il kernel che, alla fine, invia il segnale al processo. Il kernel, per identificare un processo, puo' usare sia il PID che il PGID.
Per la gestione del PID e del PGID, esistono diverse funzioni come "getpgid", "setpgid", ecc. in "/usr/include/unistd.h" (per informazioni "man getpgid", ecc.).

Tenendo conto che un segnale e' identificato da un numero, i parametri accettati da "kill" sono due: il PID del processo che deve ricevere il segnale ed il numero del segnale stesso, entrambi interi.
Un esempio:

#include <signal.h>
...
int errore=0;
...
//invia il segnale e riporta l'eventuale errore.
errore=kill(40,SIGSEGV);
...
Pubblicita'
Il segnale SIGSEGV (vedi tabella, oppure il file "/usr/include/bits/signum.h") invia, al processo il cui PID e' 40 (numero inventato sul momento), l'indicazione di violazione di segmento (di memoria).
Nella variabile "errore" ci sara' "0" se il segnale e' stato inviato correttamente, "-1" altrimenti (nella variabile "errno" ci sara' il codice di errore: vedi "gestione degli errori".

Il valore del PID passato alla funzione "alarm" puo' essere anche diverso da un numero positivo: PID=0 significa che il segnale viene inviato a tutti i processi con PGID uguale a quello del mittente; PID=-1 significa che il segnale e' inviato a tutti i processi (eccetto quelli numero "0=init" e "1=scheduler") in ordine decrescente di PID (i PID vengono letti dalla tabella dei processi); PID<-1 significa che il segnale viene inviato a tutti i processi con PGID uguale al valore assoluto del PID (es. PID=-100, PGID=100).

Signal

Con la funzione "signal" e' possibile catturare i segnali che arrivano ad un processo.
Il meccanismo di utilizzo di questa funzione, prevede la conoscenza del numero di segnale e la creazione di una funzione che lo gestisca.
Un esempio:

#include <signal.h>
...
void gestoreKill()
{
  //eseguita quando viene ricevuto un kill
  ...
}
...
int main()
{
  //Inizializza l'azione assegnata al segnale SIGKILL
  signal(SIGKILL, gestoreKill);
  ...
}
Questo piccolo pseudo-programma cattura il segnale di uccisione del processo e lo gestisce in qualche modo con la funzione "gestoreKill()".
La struttura mostrata, non soddisfa, pero', tutte le esigenze: infatti, dopo che un segnale viene catturato, l'azione (meglio, la funzione) ad esso associata, viene riportata a quella di default. Cioe', nel programmino precedente, il segnale viene catturato solo la prima volta. Si puo' ovviare a questo inconveniente inserendo come prima istruzione, nella funzione "gestoreKill()", di nuovo una chiamata a "signal":
#include <signal.h>
...
void gestoreKill()
{
  //eseguita quando viene ricevuto un kill
  signal(SIGKILL, gestoreKill);
  ...
}
...
int main()
{
  //Inizializza l'azione assegnata al segnale SIGKILL
  signal(SIGKILL, gestoreKill);
  ...
}
Vi e' comunque un difetto non eliminabile completamente: il processo termina (azione di default) se interviene un SIGKILL appena prima della chiamata a "signal" nella funzione "gestoreKill()".

I segnali in arrivo possono essere anche ignorati. Per ignorare un segnale si puo' usare

signal(segnale,SIG_IGN);
Per ripristinare il segnale, gli si puo' assegnare una funzione particolare (come visto sopra) oppure si puo' ripristinare il comportamento di default:
signal(segnale,SIG_DFL);
"SIG_IGN" e "SIG_DFL" sono due particolari funzioni. La prima compie un'azione nulla. La seconda invece contiene le azioni di default per i segnali.

Il segnale "SIGKILL" non puo' essere ignorato.


La seguente tabella contiene un elenco dei segnali usabili (tratta dal file "/usr/include/bits/signum.h").

Costante Valore Significato
SIGHUP 1 Hangup (POSIX)
SIGINT 2 Interrupt (ANSI)
SIGQUIT 3 Quit (POSIX)
SIGILL 4 Illegal instruction (ANSI)
SIGTRAP 5 Trace trap (POSIX)
SIGABRT 6 Abort (ANSI)
SIGIOT 6 IOT trap (4.2 BSD)
SIGBUS 7 BUS error (4.2 BSD)
SIGFPE 8 Floating-point exception (ANSI)
SIGKILL 9 Kill, unblockable (POSIX)
SIGUSR1 10 User-defined signal 1 (POSIX)
SIGSEGV 11 Segmentation violation (ANSI)
SIGUSR2 12 User-defined signal 2 (POSIX)
SIGPIPE 13 Broken pipe (POSIX)
SIGALRM 14 Alarm clock (POSIX)
SIGTERM 15 Termination (ANSI)
SIGSTKFLT 16 Stack fault
SIGCLD SIGCHLD Same as SIGCHLD (System V)
SIGCHLD 17 Child status has changed (POSIX)
SIGCONT 18 Continue (POSIX)
SIGSTOP 19 Stop, unblockable (POSIX)
SIGTSTP 20 Keyboard stop (POSIX)
SIGTTIN 21 Background read from tty (POSIX)
SIGTTOU 22 Background write to tty (POSIX)
SIGURG 23 Urgent condition on socket (4.2 BSD)
SIGXCPU 24 CPU limit exceeded (4.2 BSD)
SIGXFSZ 25 File size limit exceeded (4.2 BSD)
SIGVTALRM 26 Virtual alarm clock (4.2 BSD)
SIGPROF 27 Profiling alarm clock (4.2 BSD)
SIGWINCH 28 Window size change (4.3 BSD, Sun)
SIGPOLL SIGIO Pollable event occurred (System V)
SIGIO 29 I/O now possible (4.2 BSD)
SIGPWR 30 Power failure restart (System V)
SIGUNUSED 31 ---

Hai trovato utile questo articolo?
Aiutami a condividerlo o metti un "mi piace".
Grazie mille!


Gli strumenti di condivisione (Google+, Facebook) sono visibili in alto a destra solo dopo aver accettato la policy di utilizzo dei cookie per questo sito.
FAQ - Come faccio a cambiare la mia scelta?

 

Strumenti (myjsp.feelinglinux.com)
Gioco: allenamento con la tastiera Strumenti di codifica/decodifica URI (%-encoding) e Base64 Strumenti di calcolo online per IP e Reti
QUIZ GAME
Quiz game

Cerca @myjsp.feelinglinux.com

Pubblicita'