next up previous contents index return to home!
Next: Invio di un segnale Up: I segnali Previous: I segnali   Indice   Indice analitico

Specifica di un signal handler

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 :

signum
- Identificativo della signal di cui si vuole installare l'handler.
handler
- Puntatore alla funzione che contiene il codice dell'handler, oppure una delle due macro predefinite : SIG_IGN, che ha il significato di ignorare la signal specificata; SIG_DFL, che installa l'handler di default della signal specificata.

Valore restituito :

SIG_ERR
- In caso di errore.
old_signal
- Puntatore alla precedente signal.

Di seguito riportiamo un piccolo esempio di come settare un nuovo handler per la signal di identificativo SIGUSR1 :

Esempio

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, 

struct sigaction *oldct);



Argomenti in ingresso :

signum
- Identificativo del segnale di cui si vuole installare l'handler.

act
- Puntatore alla struttura contenente i parametri che specificano il comportamento del nuovo handler.

oldact
- Puntatore alla struttura in cui, se diverso da NULL, vengono salvate le informazioni riguardanti il vecchio handler.

Valore restituito :

0
- In caso di successo.
-1
- In caso di errore

Come si nota le descrizioni dei signal handler sono fornite tramite la struttura di tipo struct sigaction, così definita:



#include<signal.h>


struct sigaction { 

void (*sa_handler)();
sigset_t sa_mask;
int sa_flags;
}


Significato dei vari campi :

sa_handler
- Puntatore al codice del nuovo handler.

sa_mask
- Maschera dei signal che devono essere bloccati durante l'esecuzione dell'handler.

sa_flags
- Flags per specificare il comportamento del sistema durante l'esecuzione dell'handler.

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() :

Esempio

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)
int sigfillset(sigset_t *set)
int sigaddset(sigset_t *set, int signum)
int sigdelset(sigset_t *set, int signum)
int sigismember(const sigset_t *set, int signum)


Descrizione delle funzioni :

sigemptyset
- Modifica la struttura set in modo che tutti i segnali siano mascherati.
sigfillset
- Modifica la struttura set in modo che tutti i signal siano attivi.
sigaddset
- Aggiunge alla struttura set il signal signum, ossia lo rende attivo.
sigdelset
- Maschera il signal signum nella struttura set.
sigismember
- Controlla se il signal signum è attivato o mascherato nella struttura signum.

Valore restituito :

0
- In caso di successo.
-1
- In caso di errore.
La funzione sigismember() fa eccezione ed restituisce i seguenti valori:
1
- Se il signal signum è attivato nella struttura set.
0
- Se il signal signum è mascherato nella struttura set.
-1
- In caso di errore.


next up previous contents index
Next: Invio di un segnale Up: I segnali Previous: I segnali   Indice   Indice analitico
Giuseppe Lipari 2002-10-27