Ad ogni processo è assegnata una tabella dei segnali, che fa parte del suo stato privato e specifica l'azione che il processo deve eseguire in risposta ad un segnale. Al momento della creazione del processo, ad ogni segnale è assegnato un comportamento di default, che può essere cambiato tramite un'apposita system call. Storicamente, i sistemi Unix prevedono la funzione signal(), che permette di assegnare un signal handler (tipicamente, una funzione del tipo void f(int s)) al segnale specificato e ritorna il signal handler precedentemente assegnato al segnale, sempre sotto forma di un puntatore a una funzione.
|
#include<signal.h>
void (*signal(int signum, void (*handler)(int)))(int);
|
Argomenti in ingresso :
Valore restituito :
Di seguito riportiamo un piccolo esempio di come settare un nuovo handler per la signal di identificativo SIGUSR1 :
Il comportamento di questa syscall non è però standard, in quanto in alcuni sistemi il signal handler viene resettato al valore di default quando una signal scatta, mentre su altri rimane settato al valore specificato dalla signal anche in seguito allo scattare del segnale (Linux permette entrambe le semantiche, semplicemente linkando librerie differenti; al solito, riferirsi alla man page).
Per evitare questo problema, lo standard POSIX definisce una nuova chiamata di sistema, sigaction, che è standard e quindi un programma scritto utilizzando tale chiamata è sicuramente più portabile. Qui di seguito riportiamo il prototipo della sigaction:
|
#include<signal.h> int sigaction(int signum, const struct sigaction *act,
|
Valore restituito :
Come si nota le descrizioni dei signal handler sono fornite tramite la struttura di tipo struct sigaction, così definita:
|
#include<signal.h>
struct sigaction {
|
Per installare un nuovo handler vanno quindi fatti i seguenti passi :
Nell'esempio seguente si mostra come installare un handler usando la semantica della sigaction() :
Nell'esempio sopra è introdotta la funzione sigemptyset(). Questa fa parte di una famiglia di funzioni che servono per settare correttamente il campo sa_mask della struttura sigaction. Questo campo serve per specificare il comportamento dell'handler in caso di annidamento dei segnali. Può capitare, infatti, che scatti un segnale mentre il task sta eseguendo l'handler relativo ad un altro. In questo caso il programmatore ha due possibilità:
Si può specificare tale comportamento per ogni handler installato e questo e' fatto tramite una famiglia di funzioni di cui la sigemptyset() è solo una delle appartanenti. Tali funzioni operano su una struttura di tipo struct sigset_t che contiene tutte le informazioni relative ai signal da mascherare e che, come visto, è uno dei campi della sigaction.
La struttura struct sigset_t è un cosiddetto tipo opaco: in altre parole, un programma non deve modificare direttamente il valore dei suoi campi (che il programmatore non dovrebbe neanche conoscere), ma può accedere ad essa solo attraverso un insieme di macro o funzioni che definiscono l'em interfaccia del tipo. In particolare, l'interfaccia della struct sigset_t è la seguente:
|
#include<signal.h>
int sigemptyset(sigset_t *set)
|
Descrizione delle funzioni :
Valore restituito :