Correzioni minime
[gapil.git] / signal.tex
index 0e1c42a1c850a29fb70ef7c7d0af6e5857887edd..1fb456973a7ce88513f71146e5eaa9be970cb2ef 100644 (file)
@@ -19,6 +19,7 @@ di generazione fino ad esaminare in dettaglio funzioni e le metodologie di
 gestione.
 
 
+
 \section{Introduzione}
 \label{sec:sig_intro}
 
@@ -1285,7 +1286,7 @@ aspettare.
 In alcune implementazioni inoltre l'uso di \func{sleep} può avere conflitti
 con quello di \macro{SIGALRM}, dato che la funzione può essere realizzata con
 l'uso di \func{pause} e \func{alarm} (in maniera analoga all'esempio che
-vedremo in \ref{sec:sig_example}). In tal caso mescolare chiamata di
+vedremo in \secref{sec:sig_example}). In tal caso mescolare chiamata di
 \func{alarm} e \func{sleep} o modificare l'azione di \macro{SIGALRM}, può
 causare risultati indefiniti. Nel caso delle \acr{glibc} è stata usata una
 implementazione completamente indipendente e questi problemi non ci sono.
@@ -1387,7 +1388,7 @@ padre.\footnote{in realt
   il nome di \macro{SIGCLD} come sinonimo di \macro{SIGCHLD}.} In generale
 dunque, quando non interessa elaborare lo stato di uscita di un processo, si
 può completare la gestione della terminazione installando un manipolatore per
-\macro{SIGCHLD} il cui unico compito sia quello chiamare \func{wait} per
+\macro{SIGCHLD} il cui unico compito sia quello chiamare \func{waitpid} per
 completare la procedura di terminazione in modo da evitare la formazione di
 zombie.
 
@@ -1442,7 +1443,7 @@ void Hand_CHLD(int sig)
 \end{figure}
 
 Il codice del manipolatore è di lettura immediata; come buona norma di
-programmazione (si ricordi quanto accennato \ref{sec:sys_errno}) si comincia
+programmazione (si ricordi quanto accennato \secref{sec:sys_errno}) si comincia
 (\texttt{\small 13}) con il salvare lo stato corrente di \var{errno}, in modo
 da poterla ripristinare prima del ritorno del manipolatore (\texttt{\small
   23}). In questo modo si preserva il valore della variabile visto dal corso
@@ -1460,16 +1461,25 @@ della generazione di altri segnali dello stesso tipo. In questo caso
 normalmente i segnali vengono ``fusi'' insieme ed al processo ne viene
 recapitato soltanto uno.
 
-Questo può essere un caso comune proprio con \texttt{SIGCHLD}, quando molti
-processi figli terminano in rapida successione, e si presenta comunque tutte
-le volte che un segnale viene bloccato. Nel nostro caso se si chiamasse
-\func{waitpid} una sola volta si correrebbe il rischio di non leggere lo stato
-di uscita di tutti i processi effettivamente terminati, i cui segnali sono
-stati riuniti in uno solo. Per questo il ciclo di (\texttt{\small 15--21})
-ripete la lettura (eseguita con il parametro \macro{WNOHANG}, che permette di
-evitare il blocco della funzione) fintanto che essa non restitusce un valore
-nullo, segno che non resta nessun processo concluso di cui si debba ancora
-ricevere lo stato di terminazione.
+Questo può essere un caso comune proprio con \macro{SIGCHLD}, quando molti
+processi figli terminano in rapida successione. Esso comunque si presenta
+tutte le volte che un segnale viene bloccato: per quanti siano i segnali
+emessi durante il periodo di blocco, una volta che esso viene rimosso ne sarà
+recapitato uno solo.
+
+Nel caso della terminazione dei processi figli, se si chiamasse \func{waitpid}
+una sola volta, essa leggerebbe un solo stato di teminazione, anche se i
+processi terminati sono più di uno, con relativa possibilità di avere zombie
+che non vengono eliminati. 
+
+Per questo si esegue un ciclo (\texttt{\small 15--21}) in cui ripete la
+lettura fintanto che essa non restituisce un valore nullo (si veda
+\secref{sec:proc_wait} per la sintassi della funzione) segno che non resta
+nessun processo di cui si debba ancora ricevere lo stato di terminazione. Si
+noti come la funzione viene invocata con il parametro \macro{WNOHANG} che
+permette di evitare che essa si blocchi quando tutti gli stati di terminazione
+sono stati ricevuti.
+
 
 
 \section{Gestione avanzata}
@@ -1482,7 +1492,9 @@ che i segnali possono generare e alla natura asincrona degli stessi.
 
 Affronteremo queste problematiche in questa sezione, partendo da un esempio
 che le evidenzi, per poi prendere in esame le varie funzioni che permettono di
-risolvere i problemi più complessi connessi alla programmazione con i segnali.
+risolvere i problemi più complessi connessi alla programmazione con i segnali,
+fino a trattare le caratteristiche generali della gestione dei medesimi nella
+casistica ordinaria.
 
 
 \subsection{Un esempio di problema}
@@ -1494,6 +1506,13 @@ vista questo pu
 semplice versione di \func{sleep} potrebbe essere la seguente quella
 illustrata in \ref{fig:sig_sleep_wrong}.
 
+In questo caso si salva il precedente manipolatore in (\texttt{\small 15--21})
+per poi chiamare in sequenza \func{alarm} per specificare l'attesa e
+\func{pause} per fermare il programma. Al ritorno di pause, causato dal
+ritorno del manipolatore (\texttt{\small 15--21}) si ripristina il
+manipolatore (\texttt{\small 15--21}) restituendo l'eventuale tempo rimanente
+(\texttt{\small 15--21}).
+
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
@@ -1524,21 +1543,72 @@ void alarm_hand(int sig) {
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{Una implementazione sbagliata di \func{sleep}.} 
+  \caption{Una implementazione pericolosamente sbagliata di \func{sleep}.} 
   \label{fig:sig_sleep_wrong}
 \end{figure}
 
-Ma questa funzione, a parte il non gestire il caso in cui si è avuta una
+Ma questo codice, a parte il non gestire il caso in cui si è avuta una
 precedente chiamata a \func{alarm}, presenta una pericolosa race condition.
 Infatti se il processo viene interrotto fra la chiamata di \func{alarm} e
-\func{pause} può capitare (nel caso il sistema sia molto carico) che
+\func{pause} può capitare (ad esempio se il sistema è molto carico) che
 quest'ultima possa essere eseguita dopo l'arrivo di \macro{SIGALRM}. In questo
 caso ci si troverebbe di fronte ad un deadlock, in cui \func{pause} non
-verrebbe mai interrotta (se non in caso di un altro segnale).
+verrebbe mai più interrotta (se non in caso di un altro segnale).
 
-Come abbiamo accennato in \secref{sec:proc_atom_oper} quando si ha a che fare
-con i segnali 
+Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
+SVr2) usando la funzione \func{longjump} (vedi \secref{sec:proc_longjmp}) per
+uscire dal manipolatore; in questo modo, usando lo stato di uscita di
+quest'ultima, si può evitare la chiamata a \func{pause}, con un codice come
+quello riportato in \ref{fig:sig_sleep_incomplete}.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}{}
+static jmp_buff alarm_return;
+unsigned int sleep(unsigned int seconds)
+{
+    signandler_t prev_handler;
+    if ((prev_handler = signal(SIGALRM, alarm_hand)) == SIG_ERR) {
+        printf("Cannot set handler for alarm\n");
+        exit(1);
+    }
+    if (setjmp(alarm_return) == 0) { /* if not returning from handler */
+        alarm(second);      /* call alarm */
+        pause();            /* then wait */
+    }
+    /* restore previous signal handler */
+    signal(SIGALRM, prev_handler);
+    /* remove alarm, return remaining time */
+    return alarm(0);
+}
+void alarm_hand(int sig) {
+    /* check if the signal is the right one */
+    if (sig != SIGALRM) { /* if not exit with error */
+        printf("Something wrong, handler for SIGALRM\n");
+        exit(1);
+    } else {    /* return in main after the call to pause */
+        longjump(alarm_return, 1);
+    }
+}      
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{Una implementazione ancora malfunzionante di \func{sleep}.} 
+  \label{fig:sig_sleep_incomplete}
+\end{figure}
 
+In questo caso il manipolatore non ritorna come in \ref{fig:sig_sleep_wrong},
+ma usa \func{longjmp} (\texttt{\small 15--21}) per rientrare nel corpo
+principale del programma; dato che in questo caso il valore di uscita di
+\func{setjmp} è 1 grazie alla condizione in (\texttt{\small 15--21}) si evita
+in ogni caso che \func{pause} sia chiamata a vuoto.
+
+Ma anche questa implementazione comporta dei problemi; in questo caso infatti
+non viene gestita correttamente l'interazione con altri segnali; se infatti il
+segnale di allarme interrompe un altro manipolatore, in questo caso
+l'esecuzione non riprenderà nel manipolatore in questione, ma nel ciclo
+principale, interrompendone inopportunamente l'esecuzione.