Aggiunto esempio di gestione di segnali con la semantica BSD per il restart
authorSimone Piccardi <piccardi@gnulinux.it>
Tue, 6 May 2003 11:29:16 +0000 (11:29 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Tue, 6 May 2003 11:29:16 +0000 (11:29 +0000)
delle system call

elemtcp.tex
listati/SignalRestart.c [new file with mode: 0644]
signal.tex
sources/Gapil.h
sources/SigHand.c

index 534dd398f18819943c1811ed5bbb63fcf5d556ab..766974ff749966578a05de3f57d0230ed07c7a84 100644 (file)
@@ -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 (file)
index 0000000..89bc502
--- /dev/null
@@ -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);
+}
index 7a680d40d0e77c7fed49f7185c8e054a1ea4dd6f..dca91653837ba38ea38b9aa402b75ea2a1a8c249 100644 (file)
@@ -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}
 
index 60b411a7aa9c2c452ca7ae2c238316f63005280d..0db517d6a712fc4fd1207c067bb5223a88fa016e 100644 (file)
@@ -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 <sys/sem.h>                           /* 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);
 /* 
index 89585e3cc63c3f3e485aca5a4017fae8288414f3..3fb588a99458b1903cded34effa155f5159b6504 100644 (file)
@@ -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 <errno.h>                               /* error simbol definitions */
 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)
 {