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.
 
 
 gestione.
 
 
+
 \section{Introduzione}
 \label{sec:sig_intro}
 
 \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
 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.
 \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
   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.
 
 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
 \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
 (\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.
 
 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}
 
 
 \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
 
 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}
 
 
 \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}.
 
 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}
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
@@ -1524,21 +1543,72 @@ void alarm_hand(int sig) {
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
     \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}
 
   \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
 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
 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.