From: Simone Piccardi Date: Tue, 6 May 2003 11:29:16 +0000 (+0000) Subject: Aggiunto esempio di gestione di segnali con la semantica BSD per il restart X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=7b6b988cdddf6e996eb88d02bd13bbe7e2936d73 Aggiunto esempio di gestione di segnali con la semantica BSD per il restart delle system call --- diff --git a/elemtcp.tex b/elemtcp.tex index 534dd39..766974f 100644 --- a/elemtcp.tex +++ b/elemtcp.tex @@ -2005,14 +2005,63 @@ Baster \noindent all'esempio illustrato in \figref{fig:TCP_echo_server_code}. -In questo modo però si introduce un altro problema, +In questo modo però si introduce un altro problema, il fatto che, come +spiegato in \secref{sec:sig_gen_beha}, quando un programma si trova in stato +di \texttt{sleep} durante l'esecuzione di una system call, questa viene +interrotta alla ricezione di un segnale, per cui alla fine dell'esecuzione del +gestore il programma, se questo ritorna, l'esecuzione del programma riprenderà +con l'uscita dalla system call con un errore di \errcode{EINTR}. + +Questo comporta che quando si chiude il client, con la terminazione del +processo figlio, il padre, che riceve il segnale ed esegue il gestore, +ritornerà dalla \func{accept} (a meno di un caso fortuito in cui il segnale +arriva durante l'esecuzione del programma in risposta ad una connessione) con +un errore di \errcode{EINTR}, terminando a sua volta con un errore del tipo: +\begin{verbatim} + +\end{verbatim} -\subsection{I vari scenari critici} -\label{sec:TCP_echo_critical} +Come accennato in \secref{sec:sig_gen_beha} questo ci mette di fronte a due +possibili soluzioni, la più semplice è quella di modificare il codice di +\func{Signal} per richiedere il riavvio automatico delle system call +interrotte secondo la semantica di BSD, usando l'opzione \const{SA\_RESTART} +di \func{sigaction}; rispetto a quanto visto in \figref{fig:sig_Signal_code} +definiremo allora la nuova funzione \func{SignalRestart} come mostrato in +\figref{fig:sig_SignalRestart_code}. +\begin{figure}[!htb] + \footnotesize \centering + \begin{minipage}[c]{15.6cm} + \includecodesample{listati/SignalRestart.c} + \end{minipage} + \normalsize + \caption{La funzione \funcd{SignalRestart}, che installa un gestore di + segnali in semantica BSD.} + \label{fig:sig_SignalRestart_code} +\end{figure} + +Come si può notare questa funzione è identica a \func{Signal}, solo che in +questo caso invece di inizializzare a zero il campo \var{sa\_flags} di +\struct{sigaction} lo si inizializza (\texttt{\small 5}) al valore +\const{SA\_RESTART}. + +Usando questa funzione al posto di \func{Signal} nel server non è necessaria +nessuna altra modifica, le system call interrotte saranno automaticamente +riavviate, e l'errore \errcode{EINTR} non si manifesterà più. + + + +\section{I vari scenari critici} +\label{sec:TCP_echo_critical} +Con le modifiche viste in \secref{sec:TCP_child_hand} il nostro esempio +diventa in grado di affrontare correttamente la gestione ordinaria delle +connessioni, ma un server di rete deve tenere conto che, al contrario di +quanto avviene per i server che operano nei confronti di processi presenti +sulla stessa macchina, la rete è di sua natura inaffidabile, per cui è +necessario essere in grado di gestire tutta una serie di situazioni critiche. diff --git a/listati/SignalRestart.c b/listati/SignalRestart.c new file mode 100644 index 0000000..89bc502 --- /dev/null +++ b/listati/SignalRestart.c @@ -0,0 +1,15 @@ +inline SigFunc * SignalRestart(int signo, SigFunc *func) +{ + struct sigaction new_handl, old_handl; + new_handl.sa_handler = func; /* set signal handler */ + new_handl.sa_flags = SA_RESTART; /* restart system call */ + /* clear signal mask: no signal blocked during execution of func */ + if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */ + return SIG_ERR; + } + /* change action for signo signal */ + if (sigaction(signo, &new_handl, &old_handl)){ + return SIG_ERR; + } + return (old_handl.sa_handler); +} diff --git a/signal.tex b/signal.tex index 7a680d4..dca9165 100644 --- a/signal.tex +++ b/signal.tex @@ -1834,8 +1834,8 @@ sempre il caso di evitare l'uso di \func{signal} a favore di \func{sigaction}. \includecodesample{listati/Signal.c} \end{minipage} \normalsize - \caption{Una funzione equivalente a \func{signal} definita attraverso - \func{sigaction}.} + \caption{La funzione \funcd{Signal}, equivalente a \func{signal}, definita + attraverso \func{sigaction}.} \label{fig:sig_Signal_code} \end{figure} diff --git a/sources/Gapil.h b/sources/Gapil.h index 60b411a..0db517d 100644 --- a/sources/Gapil.h +++ b/sources/Gapil.h @@ -23,7 +23,7 @@ * * Author: S. Piccardi * - * $Id: Gapil.h,v 1.10 2003/05/02 09:56:41 piccardi Exp $ + * $Id: Gapil.h,v 1.11 2003/05/06 11:29:16 piccardi Exp $ * *****************************************************************************/ #include /* IPC semaphore declarations */ @@ -91,6 +91,8 @@ inline int UnlockFile(const char* path_name); typedef void SigFunc(int); /* Function Signal: Initialize a signal handler. See SigHand.c */ SigFunc * Signal(int signo, SigFunc *func); +/* Function SignalRestart: restart system calls. See SigHand.c */ +SigFunc * SignalRestart(int signo, SigFunc *func); /* Function HandSigCHLD: to handle SIGCHILD. See SigHand.c */ void HandSigCHLD(int sig); /* diff --git a/sources/SigHand.c b/sources/SigHand.c index 89585e3..3fb588a 100644 --- a/sources/SigHand.c +++ b/sources/SigHand.c @@ -22,7 +22,7 @@ * * Author: S. Piccardi Dec. 2002 * - * $Id: SigHand.c,v 1.5 2003/05/02 09:55:14 piccardi Exp $ + * $Id: SigHand.c,v 1.6 2003/05/06 11:29:16 piccardi Exp $ * *****************************************************************************/ #include /* error simbol definitions */ @@ -49,24 +49,55 @@ inline SigFunc * Signal(int signo, SigFunc *func) { struct sigaction new_handl, old_handl; - new_handl.sa_handler = func; /* set signal handler */ + new_handl.sa_handler = func; /* set signal handler */ /* clear signal mask: no signal blocked during execution of func */ - if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */ + if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */ return SIG_ERR; } - new_handl.sa_flags=0; /* init to 0 all flags */ + new_handl.sa_flags=0; /* init to 0 all flags */ /* change action for signo signal */ - if (sigaction(signo,&new_handl,&old_handl)){ + if (sigaction(signo, &new_handl, &old_handl)){ return SIG_ERR; } return (old_handl.sa_handler); } + +/* + * Function SignalRestart + * Initialize a signal handler. + * To enable the signal handling a process we need to tell it to + * kernel; this is done writing all needed info to a sigaction structure + * named sigact, and then callind sigaction() system call passing the + * information stored in the sigact structure variable. + * This version enable BSD semantics with SA_RESTART + * + * Input: the signal to handle + * the signal handler function + * Return: the previous sigaction structure + */ +inline SigFunc * SignalRestart(int signo, SigFunc *func) +{ + struct sigaction new_handl, old_handl; + new_handl.sa_handler = func; /* set signal handler */ + new_handl.sa_flags = SA_RESTART; /* restart system call */ + /* clear signal mask: no signal blocked during execution of func */ + if (sigemptyset(&new_handl.sa_mask)!=0){ /* initialize signal set */ + return SIG_ERR; + } + /* change action for signo signal */ + if (sigaction(signo, &new_handl, &old_handl)){ + return SIG_ERR; + } + return (old_handl.sa_handler); +} + + /* * Functions: HandSigCHLD * Generic handler for SIGCHLD signal * * Simone Piccardi Dec. 2002 - * $Id: SigHand.c,v 1.5 2003/05/02 09:55:14 piccardi Exp $ + * $Id: SigHand.c,v 1.6 2003/05/06 11:29:16 piccardi Exp $ */ void HandSigCHLD(int sig) {