danny block notes

domenica, 1 luglio 2007

Unix Programming : Segnali

Filed under: c,linux,programming — danny @ 2:47 pm
Tags: , ,
/* SEGNALI : EVENTI ASINCRONI */

/* sono segnalazioni asincrone generate in genere dal SO e da altri processi.
se non vengono gestite viene applicato il comportamento di default : chiusura del processo.
possibilità di gestione :
1. cattura del segnale   (e si esegue una certa routine)
2. ignoramento esplicito (non possibile per tutti i segnali es. SIGKILL)
2. ignoramento implicito (comp. di default)
Segnali più utilizzati:
SIGINT  : interrupt CTRL-C
SIGPIPE : già visto sopra
SIGALRM : inviato allo scadere di un timeout
SIGHUP  : si chiude il terminale
SIGTERM : chiusura non forzata processo
SIGUSRx : x=1,2,... definito dall'utente
*/

int kill (int pid, int segnale)
// non è la kill!!! ma serve per generare un segnale da inviare al processo pid
// tranne che se si è root, si possono inviare segnali solo a processi dello stesso utente
// è asincrona non bloccante.
// -1 in caso di fallimento

int raise(int segnale)
// invia un segnale al proesso corrente
// come kill (getpid(),sengale)

unsigned int alarm(unsigned int seconds);
// programma un timer interno al sistema operativo che invia al processo stesso un segnale SIGALRM dopo seconds secondi.
// restituisce il numero di secondi rimanenti alla generazione di un evento  impostato da una precedente chiamata ad alarm.
// Effettuare una chiamata ad alarm quando ne era stata già effettuata un�altra imposta il valore del timer
// pari a quello nell�ultima chiamata.

void (* signal(int sig, void (*func)(int))) (int);
// cattura il segnale sig e lancia la funzione func:
// func: puntatore alla funzione di gestione del segnale oppure SIG_DFL/SIG_IGN.
// ritorna SIG_ERR in caso di errore, altrimenti il valore della precedente funzione
// di gestione del segnale che viene sovrascritto con func.
//    SIG_DFL impone al processo il comportamento di default.
//    SIG_IGN impone al processo di ignorare esplicitamente il segnale.

int pause(void);
// blocca il processo in attesa di un qualsiasi segnale.
// ritorna sempre -1 e dopo la eventuale funzione di gestione (in una signal)
// non è possibile sapere direttamente da pause quale segnale ha provocato lo sblocco;
// si può rimediare facendo si che l�handler del segnale modifichi il valore di
// una variabile globale.

/* NOTE:
1. I processi figli ereditano le eventuali gestioni dei segnali (tranne se si ha una exec).
2. Possono interrompere sia funzioni di programma sia systemcall bloccanti, in questo caso
la chiamata non viene ripetuta e la variabile globale errno viene settata a EINTR.
Questo implica che la corretta invocazione di una systemcall bloccante è :
while ( systemCall() == -1 )
if ( errno != EINTR ) {
printf (�Errore!\\n�);
exit(1);
}
Infatti lo schema seguente non basta :
if ( systemCall() == -1 ) {
printf (�Errore!\\n�);
exit(1);
}
*/

/* LA GESTIONE DEI SEGNALI VISTA FINORA è INAFFIDABILE POICHé PUò GENERARE DEADLOCK!!!
questo poichè non si gestiscono segnali che possono arrivare in un breve lasso di tempo,
eventualmente minore del tempo di esecuzione dell'handler di gestione.
Per questo un processo può bloccare temporaneamente la consegna di un segnale (tranne SIGKILL).
In pratica si crea un accodamento gestito dalla SIGNAL MASK cioè una maschera che indica quali segnali
si stanno bloccando.
Si lavora sulla Signal Mask attraverso la struttura SIGSET_T ed alle funzioni : */

int sigemptyset (sigset_t *set);
// Svuota set.
int sigfillset (sigset_t *set);
// Mette tutti i segnali in set.
int sigaddset (sigset_t *set, int signo);
// Aggiunge il segnale signo a set.
int sigdelset (sigset_t *set, int signo);
// Toglie il segnale signo da set.
int sigismember (sigset_t *set, int signo);
// Controlla se signo è in set.

int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
// modifica la signal mask.
// how: indica in che modo intervenire sulla signal mask e può valere:
//     SIG_BLOCK: i segnali indicati in set sono aggiunti alla signal mask;
//    SIG_UNBLOCK: i segnali indicati in set sono rimossi dalla signal mask;
//    SIG_SETMASK: La nuova signal mask diventa quella specificata da set;
// set: il signal set sulla base del quale verranno effettuate le modifiche.
// oset: se non è NULL, il backup della signal mask attuale/precedente
// -1 in caso di errore.

int sigpending(sigset_t *set);
// restituisce l�insieme dei segnali bloccati che sono attualmente pendenti.
// set: il signal set in cui verrà scritto l�insieme dei segnali pendenti.
// -1 in caso di errore.

int sigaction( int sig,
const struct sigaction * restrict act,
struct sigaction * restrict oact);
// Permette di esaminare e/o modificare l�azione associata ad un segnale.
// sig: il segnale interessato dalla modifica;
// act: indica come modificare la gestione del segnale;
// oact: backup della precedente struttura sigaction
// -1 in caso di errore.

struct sigaction {
void (*sa_handler)();
/* indirizzo del gestore o SIG_IGN o SIG_DFL*/
void (*sa_sigaction)(int, siginfo_t *, void*);
/* indirizzo del gestore che riceve informazioni addizionali
sul segnale ricevuto (utilizzato al posto di sa_handler se
sa_flags contiene SA_SIGINFO ) */
sigset_t sa_mask;
/* segnali addizionali da bloccare prima dell'esecuzione del gestore */
int sa_flags;
/* opzioni addizionali */
};

/* Notifiche (eventualmente multiple) dello stesso segnale durante l�esecuzione del
gestore sono bloccate fino al termine del gestore stesso (a meno che sa_flags valga NO_DEFER).
Con l�uso di sigaction l�azione specificata per il trattamento di un segnale rimane
attiva fino ad una successiva modifica.
*/

int sigsuspend(const sigset_t *sigmask);
// attende l�arrivo di un segnale.
// sigmask: prima di mettersi in attesa la funzione rende attiva questa signal mask;
// torna sempre -1 con errno che vale EINTR.
// una volta terminata, ripristina la signal mask precedente alla sua chiamata.
// Quando viene attivata, se esistono segnali pendenti che vengono sbloccati da
// sigmask, questi vengono immediatamente consegnati.
// Se non esistono segnali pendenti, oppure questi non vengono sbloccati, la funzione
// mette il processo in attesa dell�arrivo di un qualsiasi segnale non bloccato.

// ESEMPIO : passi da seguire per una gestione sicura dei segnali

// 1. definire l'handler di gestione
void myhandler(...)

// 2. dichiarazione strutture necessarie nel main
struct sigaction sig, oldsig;
sigset_t sigmask, oldmask, zeromask;
// le old sono solo di backup...potrebbe esser necessario utilizzarle (null altrimenti nelle successive chiamate)
// zeromask è una sigmask vuota che utilizziamo per disattivare il blocco

// 3. inizializzazione : blocco del segnale SIGUSR1
sigemptyset(&zeromask);

sigemptyset(&sigmask);
sigaddset(&sigmask,SIGUSR1);
sigprocmask(SIGBLOCK, &sigmask, &oldmask);
// ho aggiunto il sigset sigmask all'insieme dei segnali da bloccare

// 4. inizializzazione gestore di segnale
sig.sa_handler = myhandler;
sig.sa_flags = 0;
sigemptyset(&sig.sa_mask);
// sono segnali addizionali da bloccare prima del gestore...dipende dal programma

sigaction(SIGUSR1,&sig,&oldsig)
// quello che faceva la signal ma lo indirizzo al gestore e non direttamente all'handler

// 5. dipende dal programma :
// a questo punto in genere si creano i processi figli considerando che fin qui i segnali SIGUSR1 sono bloccati.
// se per esempio il figlio dovesse fare qualcosa ed inviare un segnale al padre allora una volta finito il suo lavoro :
kill(getppid(),SIGUSR1);
// sblocca il segnale qualora anche lui dovesse ricevere un segnale dal padre
sigsuspend(&zeromask);
// in pratica si mette in attesa di segnali rendendo attiva zeromask (che è vuota quindi non blocca niente)
// e ripristinando poi la sigmask precedente alla chiamata (quella che blocca SIGUSR1)
// il padre analogamente prima sblocca il segnale fa quello che deve fare ed eventualmente manda un segnale di risp al figlio
Annunci

Lascia un commento »

Non c'è ancora nessun commento.

RSS feed for comments on this post. TrackBack URI

Rispondi

Inserisci i tuoi dati qui sotto o clicca su un'icona per effettuare l'accesso:

Logo WordPress.com

Stai commentando usando il tuo account WordPress.com. Chiudi sessione / Modifica )

Foto Twitter

Stai commentando usando il tuo account Twitter. Chiudi sessione / Modifica )

Foto di Facebook

Stai commentando usando il tuo account Facebook. Chiudi sessione / Modifica )

Google+ photo

Stai commentando usando il tuo account Google+. Chiudi sessione / Modifica )

Connessione a %s...

Blog su WordPress.com.

%d blogger hanno fatto clic su Mi Piace per questo: