Iniziata sigaction
[gapil.git] / signal.tex
index bbfea4f851f101561bc6adecfae0aaddd5b0f368..98e476eb52ef57e99ef2390f23b4b12bfd916482 100644 (file)
@@ -84,22 +84,8 @@ attivo.
 In questo caso è possibile una situazione in cui i segnali possono essere
 perduti. Si consideri il seguente segmento di codice, in cui la prima
 operazione del manipolatore è quella di reinstallare se stesso: 
 In questo caso è possibile una situazione in cui i segnali possono essere
 perduti. Si consideri il seguente segmento di codice, in cui la prima
 operazione del manipolatore è quella di reinstallare se stesso: 
-
-\footnotesize
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-    int sig_handler();            /* handler function */
-    ...
-    signal(SIGINT, sig_handler);  /* establish handler */
-    ...
-
-int sig_handler() 
-{
-    signal(SIGINT, sig_handler);  /* restablish handler */
-    ...                           /* process signal */
-}
-\end{lstlisting}
-\normalsize
-se un secondo segnale arriva prima che il manipolatore invocato dal primo
+s
+e un secondo segnale arriva prima che il manipolatore invocato dal primo
 abbia eseguito la reinstallazione di se stesso il segnale può essere perso o
 causare il comportamento originale assegnato al segnale (in genere la
 terminazione del processo).
 abbia eseguito la reinstallazione di se stesso il segnale può essere perso o
 causare il comportamento originale assegnato al segnale (in genere la
 terminazione del processo).
@@ -322,7 +308,6 @@ In \tabref{tab:sig_signal_list} si 
 definiti in Linux (estratto dalle man page), comparati con quelli definiti in
 vari standard.
 
 definiti in Linux (estratto dalle man page), comparati con quelli definiti in
 vari standard.
 
-
 \begin{table}[htb]
   \footnotesize
   \centering
 \begin{table}[htb]
   \footnotesize
   \centering
@@ -966,43 +951,28 @@ manipolatore potr
 \func{raise}.
 
 Se invece si vuole inviare un segnale ad un altro processo occorre utilizzare
 \func{raise}.
 
 Se invece si vuole inviare un segnale ad un altro processo occorre utilizzare
-la funzione \func{kill}; il suo prototipo è:
+la funzione \func{kill}; il cui prototipo è:
 \begin{functions}
   \headdecl{sys/types.h}
   \headdecl{signal.h}
   \funcdecl{int kill(pid\_t pid, int sig)} Invia il segnale \param{sig} al
   processo specificato con \param{pid}.
 \begin{functions}
   \headdecl{sys/types.h}
   \headdecl{signal.h}
   \funcdecl{int kill(pid\_t pid, int sig)} Invia il segnale \param{sig} al
   processo specificato con \param{pid}.
-
-  \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
-    errore, nel qual caso \var{errno} assumerà i valori:
-  \begin{errlist}
-  \item[\macro{EINVAL}] Si è specificato un numero di segnale invalido.
-  \item[\macro{EPERM}] Il processo non ha il permesso di inviare il segnale
-  alla destinazione specificata.
-  \item[\macro{ESRCH}] Il \acr{pid} o il process group indicati non
-  esistono. Gli zombie (vedi \ref{sec:proc_termination}) sono considerati come
-  processi esistenti.
-  \end{errlist}}
 \end{functions}
 
 \end{functions}
 
-La funzione \code{raise(sig)} è sostanzialmente equivalente ad una
-\code{kill(getpid(), sig)}. Siccome \func{raise}, che è definita nello
-standard ISO C, non esiste in alcune vecchie versioni di Unix, in generale
-l'uso di \func{kill} finisce per essere più portabile.
-
-Lo standard POSIX poi prevede che il valore 0 sia usato per specificare il
-segnale nullo.  Se le funzioni vengono chiamate con questo valore non viene
-inviato nessun segnale, ma viene eseguito il controllo degli errori, in tal
-caso si otterrà un errore \macro{EPERM} se non si hanno i permessi necessari
-ed un errore \macro{ESRCH} se il processo specificato non esiste. Si tenga
-conto però che il sistema ricicla i \acr{pid} (come accennato in
-\secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
+Lo standard POSIX prevede che il valore 0 per \param{sig} sia usato per
+specificare il segnale nullo.  Se le funzioni vengono chiamate con questo
+valore non viene inviato nessun segnale, ma viene eseguito il controllo degli
+errori, in tal caso si otterrà un errore \macro{EPERM} se non si hanno i
+permessi necessari ed un errore \macro{ESRCH} se il processo specificato non
+esiste. Si tenga conto però che il sistema ricicla i \acr{pid} (come accennato
+in \secref{sec:proc_pid}) per cui l'esistenza di un processo non significa che
 esso sia realmente quello a cui si intendeva mandare il segnale.
 
 Il valore dell'argomento \param{pid} specifica il processo (o i processi) di
 destinazione a cui il segnale deve essere inviato e può assumere i valori
 riportati in \tabref{tab:sig_kill_values}.
 \begin{table}[htb]
 esso sia realmente quello a cui si intendeva mandare il segnale.
 
 Il valore dell'argomento \param{pid} specifica il processo (o i processi) di
 destinazione a cui il segnale deve essere inviato e può assumere i valori
 riportati in \tabref{tab:sig_kill_values}.
 \begin{table}[htb]
+  \footnotesize
   \centering
   \begin{tabular}[c]{|r|l|}
     \hline
   \centering
   \begin{tabular}[c]{|r|l|}
     \hline
@@ -1023,6 +993,12 @@ riportati in \tabref{tab:sig_kill_values}.
 \end{table}
 
 
 \end{table}
 
 
+Si noti pertanto che la funzione \code{raise(sig)} può essere definita in
+termini di \func{kill}, ed è sostanzialmente equivalente ad una
+\code{kill(getpid(), sig)}. Siccome \func{raise}, che è definita nello
+standard ISO C, non esiste in alcune vecchie versioni di Unix, in generale
+l'uso di \func{kill} finisce per essere più portabile.
+
 Solo l'amministratore può inviare un segnale ad un processo qualunque, in
 tutti gli altri casi il \textit{real user id} o l'\textit{effective user id}
 del processo chiamante devono corrispondere al \textit{real user id} o al
 Solo l'amministratore può inviare un segnale ad un processo qualunque, in
 tutti gli altri casi il \textit{real user id} o l'\textit{effective user id}
 del processo chiamante devono corrispondere al \textit{real user id} o al
@@ -1045,9 +1021,10 @@ segnale al processo che ha effettuato la chiamata.
 \label{sec:sig_alarm_abort}
 
 Un caso particolare di segnali generati a richiesta è quello che riguarda i
 \label{sec:sig_alarm_abort}
 
 Un caso particolare di segnali generati a richiesta è quello che riguarda i
-segnali di temporizzazione e \macro{SIGABORT}, per i quali sono previste
-funzioni specifiche che ne effettuino l'invio. La prima di queste è
-\func{alarm} il cui prototipo è:
+vari segnali di temporizzazione e \macro{SIGABORT}, per ciascuno di questi
+segnali sono previste funzioni specifiche che ne effettuino l'invio. La più
+comune delle funzioni usate per la temporizzazione è \func{alarm} il cui
+prototipo è:
 \begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)}
   Predispone l'invio di \macro{SIGALARM} dopo \param{seconds} secondi.
   
 \begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)}
   Predispone l'invio di \macro{SIGALARM} dopo \param{seconds} secondi.
   
@@ -1055,22 +1032,25 @@ funzioni specifiche che ne effettuino l'invio. La prima di queste 
     precedente allarme, o zero se non c'erano allarmi pendenti.}
 \end{prototype}
 
     precedente allarme, o zero se non c'erano allarmi pendenti.}
 \end{prototype}
 
-La funzione provvede un meccanismo che consente ad un processo di predisporre
+La funzione fornisce un meccanismo che consente ad un processo di predisporre
 un'interruzione nel futuro, (ad esempio per effettuare una qualche operazione
 un'interruzione nel futuro, (ad esempio per effettuare una qualche operazione
-dopo un certo periodo di tempo), programmando l'emissione di un segnale (in
-genere \macro{SIGALARM}) dopo il numero di secondi specificato da
+dopo un certo periodo di tempo), programmando l'emissione di un segnale (nel
+caso in questione \macro{SIGALARM}) dopo il numero di secondi specificato da
 \param{seconds}.
 
 Se si specifica per \param{seconds} un valore nullo non verrà inviato nessun
 segnale; siccome alla chiamata viene cancellato ogni precedente allarme,
 \param{seconds}.
 
 Se si specifica per \param{seconds} un valore nullo non verrà inviato nessun
 segnale; siccome alla chiamata viene cancellato ogni precedente allarme,
-questo può essere usato per cancellare una programmazione precedente. La
-funzione inoltre ritorna il numero di secondi rimanenti all'invio dell'allarme
-precedentemente programmato, in modo che sia eventualmente possibile
-effettuare delle scelte in caso di necessità di più interruzioni.
+questo può essere usato per cancellare una programmazione precedente. 
+
+La funzione inoltre ritorna il numero di secondi rimanenti all'invio
+dell'allarme precedentemente programmato, in modo che sia possibile
+controllare se non si cancella un precedente allarme ed eventualmente
+predisporre le opportune misure per gestire il caso di necessità di più
+interruzioni.
 
 In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
 
 In \secref{sec:sys_unix_time} abbiamo visto che ad ogni processo sono
-associati tre tempi diversi: \textit{clock time}, \textit{user time} e
-\textit{system time}.  Per poterli calcolare il kernel mantiene per ciascun
+associati tre tempi diversi: il \textit{clock time}, l'\textit{user time} ed
+il \textit{system time}.  Per poterli calcolare il kernel mantiene per ciascun
 processo tre diversi timer:
 \begin{itemize}
 \item un \textit{real-time timer} che calcola il tempo reale trascorso (che
 processo tre diversi timer:
 \begin{itemize}
 \item un \textit{real-time timer} che calcola il tempo reale trascorso (che
@@ -1111,6 +1091,7 @@ Il valore di \param{which} permette di specificare quale dei tre timer
 illustrati in precedenza usare; i possibili valori sono riportati in
 \tabref{tab:sig_setitimer_values}.
 \begin{table}[htb]
 illustrati in precedenza usare; i possibili valori sono riportati in
 \tabref{tab:sig_setitimer_values}.
 \begin{table}[htb]
+  \footnotesize
   \centering
   \begin{tabular}[c]{|l|l|}
     \hline
   \centering
   \begin{tabular}[c]{|l|l|}
     \hline
@@ -1130,7 +1111,7 @@ illustrati in precedenza usare; i possibili valori sono riportati in
 Il valore della struttura specificata \param{value} viene usato per settare il
 timer, se il puntatore \param{ovalue} non è nullo il precedente valore viene
 salvato qui. I valori dei timer devono essere indicati attraverso una
 Il valore della struttura specificata \param{value} viene usato per settare il
 timer, se il puntatore \param{ovalue} non è nullo il precedente valore viene
 salvato qui. I valori dei timer devono essere indicati attraverso una
-struttura \var{itimerval}, definita in \ref{fig:file_stat_struct}.
+struttura \var{itimerval}, definita in \figref{fig:file_stat_struct}.
 
 La struttura è composta da due membri, il primo, \var{it\_interval} definisce
 il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla
 
 La struttura è composta da due membri, il primo, \var{it\_interval} definisce
 il periodo del timer; il secondo, \var{it\_value} il tempo mancante alla
@@ -1138,18 +1119,22 @@ scadenza. Entrambi esprimono i tempi tramite una struttura \var{timeval} che
 permette una precisione fino al microsecondo.
 
 Ciascun timer decrementa il valore di \var{it\_value} fino a zero, poi invia
 permette una precisione fino al microsecondo.
 
 Ciascun timer decrementa il valore di \var{it\_value} fino a zero, poi invia
-il segnale e resetta \var{it\_value} al valore di \var{it\_interval},
-ripetendo il ciclo; se \var{it\_interval} è nullo il timer si ferma.
+il segnale e resetta \var{it\_value} al valore di \var{it\_interval}, in
+questo modo il ciclo verrà ripetuto; se invece il valore di \var{it\_interval}
+è nullo il timer si ferma.
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-struct itimerval {
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct itimerval 
+{
     struct timeval it_interval; /* next value */
     struct timeval it_value;    /* current value */
 };
     struct timeval it_interval; /* next value */
     struct timeval it_value;    /* current value */
 };
-struct timeval {
+
+struct timeval 
+{
     long tv_sec;                /* seconds */
     long tv_usec;               /* microseconds */
 };
     long tv_sec;                /* seconds */
     long tv_usec;               /* microseconds */
 };
@@ -1165,12 +1150,13 @@ L'uso di \func{setitimer} consente dunque un controllo completo di tutte le
 caratteristiche dei timer, ed in effetti la stessa \func{alarm}, benché
 definita direttamente nello standard POSIX.1, può a sua volta essere espressa
 in termini di \func{setitimer}, come evidenziato dal manuale delle \acr{glibc}
 caratteristiche dei timer, ed in effetti la stessa \func{alarm}, benché
 definita direttamente nello standard POSIX.1, può a sua volta essere espressa
 in termini di \func{setitimer}, come evidenziato dal manuale delle \acr{glibc}
-\cite{glibc} che ne riporta la definizione in \figref{fig:sig_alarm_def}.
+\cite{glibc} che ne riporta la definizione mostrata in
+\figref{fig:sig_alarm_def}.
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
 unsigned int alarm(unsigned int seconds)
 {
     struct itimerval old, new;
 unsigned int alarm(unsigned int seconds)
 {
     struct itimerval old, new;
@@ -1178,10 +1164,12 @@ unsigned int alarm(unsigned int seconds)
     new.it_interval.tv_sec = 0;
     new.it_value.tv_usec = 0;
     new.it_value.tv_sec = (long int) seconds;
     new.it_interval.tv_sec = 0;
     new.it_value.tv_usec = 0;
     new.it_value.tv_sec = (long int) seconds;
-    if (setitimer(ITIMER_REAL, &new, &old) < 0)
+    if (setitimer(ITIMER_REAL, &new, &old) < 0) {
         return 0;
         return 0;
-    else
+    }
+    else {
         return old.it_value.tv_sec;
         return old.it_value.tv_sec;
+    }
 }
     \end{lstlisting}
   \end{minipage} 
 }
     \end{lstlisting}
   \end{minipage} 
@@ -1191,13 +1179,23 @@ unsigned int alarm(unsigned int seconds)
 \end{figure}
 
 Si deve comunque tenere presente che la precisione di queste funzioni è
 \end{figure}
 
 Si deve comunque tenere presente che la precisione di queste funzioni è
-limitata da quella del timer di sistema (in genere 10~ms). Il sistema assicura
-comunque che il segnale non sarà mai generato prima della scadenza programmata
-(l'arrotondamento cioè è sempre effettuato per eccesso). Una seconda causa di
-potenziali ritardi è che il segnale viene generato alla scadenza del timer,
-ma poi deve essere consegnato; se il processo è attivo (questo è sempre vero
-per \macro{ITIMER\_VIRT}) la consegna è immediata, altrimenti può esserci un
-ulteriore ritardo che può variare a seconda del carico del sistema.
+limitata da quella della frequenza del timer di sistema (che nel caso dei PC
+significa circa 10~ms). Il sistema assicura comunque che il segnale non sarà
+mai generato prima della scadenza programmata (l'arrotondamento cioè è sempre
+effettuato per eccesso).  
+
+Una seconda causa di potenziali ritardi è che il segnale viene generato alla
+scadenza del timer, ma poi deve essere consegnato al processo; se quest'ultimo
+è attivo (questo è sempre vero per \macro{ITIMER\_VIRT}) la consegna è
+immediata, altrimenti può esserci un ulteriore ritardo che può variare a
+seconda del carico del sistema.
+
+Questo ha una conseguenza che può indurre ad errori molto subdoli, si tenga
+conto poi che in caso di sistema molto carico, si può avere il caso patologico
+in cui un timer scade prima che il segnale di una precedente scadenza sia
+stato consegnato; in questo caso, per il comportamento dei segnali descritto
+in \secref{sec:sig_sigchld}, un solo segnale sarà consegnato.
+
 
 Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il
 valore corrente di un timer senza modificarlo, è possibile usare la funzione
 
 Dato che sia \func{alarm} che \func{setitimer} non consentono di leggere il
 valore corrente di un timer senza modificarlo, è possibile usare la funzione
@@ -1333,22 +1331,6 @@ delle strutture di tipo \var{timespec}, la cui definizione 
 \figref{fig:sig_timespec_def}, che permettono di specificare un tempo con una
 precisione (teorica) fino al nanosecondo. 
 
 \figref{fig:sig_timespec_def}, che permettono di specificare un tempo con una
 precisione (teorica) fino al nanosecondo. 
 
-\begin{figure}[!htb]
-  \footnotesize \centering
-  \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-struct timespec
-{
-    time_t  tv_sec;         /* seconds */
-    long    tv_nsec;        /* nanoseconds */
-};
-    \end{lstlisting}
-  \end{minipage} 
-  \normalsize 
-  \caption{La struttura \var{timespec} di \func{nanosleep}.} 
-  \label{fig:sig_timespec_def}
-\end{figure}
-
 La funzione risolve anche il problema di proseguire l'attesa dopo
 l'interruzione dovuta ad un segnale; infatti in tal caso in \param{rem} viene
 restituito il tempo rimanente rispetto a quanto richiesto inizialmente, e
 La funzione risolve anche il problema di proseguire l'attesa dopo
 l'interruzione dovuta ad un segnale; infatti in tal caso in \param{rem} viene
 restituito il tempo rimanente rispetto a quanto richiesto inizialmente, e
@@ -1364,6 +1346,21 @@ sia scarico ed il processa venga immediatamente rimesso in esecuzione); per
 questo motivo il valore restituito in \param{rem} è sempre arrotondato al
 multiplo successivo di 1/\macro{HZ}.
 
 questo motivo il valore restituito in \param{rem} è sempre arrotondato al
 multiplo successivo di 1/\macro{HZ}.
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct timespec {
+    time_t  tv_sec;         /* seconds */
+    long    tv_nsec;        /* nanoseconds */
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \var{timespec} di \func{nanosleep}.} 
+  \label{fig:sig_timespec_def}
+\end{figure}
+
 In realtà è possibile ottenere anche pause più precise del centesimo di
 secondo usando politiche di scheduling real time come \macro{SCHED\_FIFO} o
 \macro{SCHED\_RR}; in tal caso infatti il meccanismo di scheduling ordinario
 In realtà è possibile ottenere anche pause più precise del centesimo di
 secondo usando politiche di scheduling real time come \macro{SCHED\_FIFO} o
 \macro{SCHED\_RR}; in tal caso infatti il meccanismo di scheduling ordinario
@@ -1443,42 +1440,41 @@ 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 \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
-di esecuzione principale del processo, che sarebbe altrimenti sarebbe
-sovrascritto dal valore restituito nella successiva chiamata di \func{wait}.
+programmazione (si ricordi quanto accennato \secref{sec:sys_errno}) si
+comincia (\texttt{\small 12-13}) con il salvare lo stato corrente di
+\var{errno}, in modo da poterlo ripristinare prima del ritorno del
+manipolatore (\texttt{\small 22-23}). In questo modo si preserva il valore
+della variabile visto dal corso di esecuzione principale del processo, che
+sarebbe altrimenti sarebbe sovrascritto dal valore restituito nella successiva
+chiamata di \func{wait}.
 
 Il compito principale del manipolatore è quello di ricevere lo stato di
 terminazione del processo, cosa che viene eseguita nel ciclo in
 
 Il compito principale del manipolatore è quello di ricevere lo stato di
 terminazione del processo, cosa che viene eseguita nel ciclo in
-(\texttt{\small 15--21}).  Il ciclo è necessario a causa di una caratteristica
+(\texttt{\small 15-21}).  Il ciclo è necessario a causa di una caratteristica
 fondamentale della gestione dei segnali: abbiamo già accennato come fra la
 generazione di un segnale e l'esecuzione del manipolatore possa passare un
 fondamentale della gestione dei segnali: abbiamo già accennato come fra la
 generazione di un segnale e l'esecuzione del manipolatore possa passare un
-certo lasso di tempo; dato che questo lasso di tempo può dipendere da parecchi
-fattori esterni, niente ci assicura che il manipolatore venga eseguito prima
-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.
+certo lasso di tempo e niente ci assicura che il manipolatore venga eseguito
+prima della generazione di ulteriori segnali dello stesso tipo. In questo caso
+normalmente i segnali segnali successivi vengono ``fusi'' col primo ed al
+processo ne viene recapitato soltanto uno.
 
 
-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.
+Questo può essere un caso comune proprio con \macro{SIGCHLD}, qualora capiti
+che molti processi figli terminino in rapida successione. Esso inoltre si
+presenta tutte le volte che un segnale viene bloccato: per quanti siano i
+segnali emessi durante il periodo di blocco, una volta che quest'ultimo sarà
+rimosso sarà recapitato un solo segnale.
 
 
-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. 
+Allora nel caso della terminazione dei processi figli, se si chiamasse
+\func{waitpid} una sola volta, essa leggerebbe lo stato di teminazione per un
+solo processo, anche se i processi terminati sono più di uno, e gli altri
+resterebbero in stato di zombie per un tempo indefinito.
 
 
-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.
+Per questo occorre ripetere la chiamata di \func{waitpid} fino a che essa non
+ritorni un valore nullo, segno che non resta nessun processo di cui si debba
+ancora ricevere lo stato di terminazione (si veda \secref{sec:proc_wait} per
+la sintassi della funzione). Si noti anche come la funzione venga invocata con
+il parametro \macro{WNOHANG} che permette di evitare il suo blocco quando
+tutti gli stati di terminazione sono stati ricevuti.
 
 
 
 
 
 
@@ -1503,15 +1499,20 @@ casistica ordinaria.
 Come accennato in \secref{sec:sig_pause_sleep} è possibile implementare
 \func{sleep} a partire da dall'uso di \func{pause} e \func{alarm}. A prima
 vista questo può sembrare di implementazione immediata; ad esempio una
 Come accennato in \secref{sec:sig_pause_sleep} è possibile implementare
 \func{sleep} a partire da dall'uso di \func{pause} e \func{alarm}. A prima
 vista questo può sembrare di implementazione immediata; ad esempio una
-semplice versione di \func{sleep} potrebbe essere la seguente quella
-illustrata in \ref{fig:sig_sleep_wrong}.
+semplice versione di \func{sleep} potrebbe essere quella illustrata in
+\figref{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}).
+Dato che è nostra intenzione utilizzare \macro{SIGALARM} il primo passo della
+nostra implementazione di sarà quello di installare il relativo manipolatore
+salvando il precedente (\texttt{\small 4-7}).  Si effettuerà poi una chiamata
+ad \func{alarm} per specificare il tempo d'attesa per l'invio del segnale a
+cui segue la chiamata a \func{pause} per fermare il programma (\texttt{\small
+  8-9}) fino alla sua ricezione.  Al ritorno di \func{pause}, causato dal
+ritorno del manipolatore (\texttt{\small 15-23}), si ripristina il
+manipolatore originario (\texttt{\small 10-11}) restituendo l'eventuale tempo
+rimanente (\texttt{\small 12-13}) che potrà essere diverso da zero qualora
+l'interruzione di \func{pause} venisse causata da un altro segnale.
 
 \begin{figure}[!htb]
   \footnotesize \centering
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1543,22 +1544,25 @@ void alarm_hand(int sig) {
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{Una implementazione pericolosamente sbagliata di \func{sleep}.} 
+  \caption{Una implementazione pericolosa di \func{sleep}.} 
   \label{fig:sig_sleep_wrong}
 \end{figure}
 
   \label{fig:sig_sleep_wrong}
 \end{figure}
 
-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 (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 più interrotta (se non in caso di un altro segnale).
+Questo codice però, a parte il non gestire il caso in cui si è avuta una
+precedente chiamata a \func{alarm} (che si è tralasciato per brevità),
+presenta una pericolosa race condition.  Infatti se il processo viene
+interrotto fra la chiamata di \func{alarm} e \func{pause} può capitare (ad
+esempio se il sistema è molto carico) che il tempo di attesa scada prima
+dell'esecuzione quest'ultima, cosicchè essa sarebbe eseguita dopo l'arrivo di
+\macro{SIGALRM}. In questo caso ci si troverebbe di fronte ad un deadlock, in
+quanto \func{pause} non verrebbe mai più interrotta (se non in caso di un
+altro segnale).
 
 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
 
 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 modo da sfruttare lo stato di uscita di
-quest'ultima per evitare la chiamata a \func{pause}, con un codice del tipo:
+uscire dal manipolatore; in questo modo, con una condizione sullo stato di
+uscita di quest'ultima, si può evitare la chiamata a \func{pause}, usando un
+codice del tipo di quello riportato in \figref{fig:sig_sleep_incomplete}.
 
 \begin{figure}[!htb]
   \footnotesize \centering
 
 \begin{figure}[!htb]
   \footnotesize \centering
@@ -1597,27 +1601,96 @@ void alarm_hand(int sig) {
   \label{fig:sig_sleep_incomplete}
 \end{figure}
 
   \label{fig:sig_sleep_incomplete}
 \end{figure}
 
-In questo modo all'uscita dal manipolatore si eviterà comunque la chiamata di
-\func{pause}, dato che in questo caso il valore di uscita di \func{setjmp} è
-uno ed il condizionale in (\texttt{\small 15--21}) viene evitato.
-
+In questo caso il manipolatore (\texttt{\small 18-26}) non ritorna come in
+\figref{fig:sig_sleep_wrong}, ma usa \func{longjmp} (\texttt{\small 24}) 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 9-12}) si evita comunque che \func{pause} sia chiamata a
+vuoto.
 
 Ma anche questa implementazione comporta dei problemi; in questo caso infatti
 
 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
+non viene gestita correttamente l'interazione con gli 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
 l'esecuzione non riprenderà nel manipolatore in questione, ma nel ciclo
-principale, interrompendone inopportunamente l'esecuzione.
+principale, interrompendone inopportunamente l'esecuzione.  È per questo
+motivo che occorrono funzioni più sofisticate della semplice \func{signal} che
+permettano di gestire i segnali in maniera più completa.
 
 
 
 
 
 
-\subsection{Le funzioni \func{sigprocmask} e \func{sigpending}}
-\label{sec:sig_sigpending}
+\subsection{La funzione \func{sigaction}}
+\label{sec:sig_sigaction}
+
+Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali
+dei primi Unix, hanno dei limiti non superabili; per questo motivo lo standard
+POSIX ha introdotto una interfaccia di gestione completamente nuova, che
+permette un controllo molto più dettagliato. La funzione principale di questa
+nuova interfaccia è \func{sigaction}; il cui prototipo è:
+
+\begin{prototype}{signal.h}{int sigaction(int signum, const struct sigaction
+    *act, struct sigaction *oldact)} 
+  
+  Installa un nuovo manipolatore per il segnale \param{signum}.
+  
+  \bodydesc{La funzione restituisce zero in caso di successo e -1 per un
+    errore, nel qual caso \var{errno} assumerà i valori:
+  \begin{errlist}
+  \item[\macro{EINVAL}] Si è specificato un numero di segnale invalido o si è
+    cercato di installare il manipolatore per \macro{SIGKILL} o
+    \macro{SIGSTOP}.
+  \item[\macro{EFAULT}] Si sono specificati indirizzi non validi.
+  \end{errlist}}
+\end{prototype}
+
+La funzione serve ad installare una nuova azione per il segnale
+\param{signum}; si parla di azione e non di manipolatore come nel caso di
+\func{signal}, in quanto la funzione consente di specificare le varie
+caratteristiche della risposta al segnale, non solo la funzione del
+manipolatore.  Lo standard POSIX raccomanda di usare sempre questa funzione al
+posto di \func{signal} (che in genere viene definita tramite essa), in quanto
+offre un controllo completo, sia pure al prezzo di una maggiore complessità
+d'uso.
+
+Se il puntatore \param{act} non è nullo la funzione installa la nuova azione
+da esso specificata, se \param{oldact} non è nullo il valore dell'azione
+corrente viene restituito indietro.  Questo permette (specificando \param{act}
+nullo e \param{oldact} non nullo) di superare uno dei limiti di \func{signal},
+che non consente di ottenere l'azione corrente senza installarne una nuova.
+
+Entrambi i puntatori fanno riferimento alla struttura \var{sigaction}, che
+permette di descrivere tutte le caratteristiche dell'azione associata ad un
+segnale.  Anch'essa è descritta dallo standard POSIX ed in Linux è definita
+secondo quanto riportato in \secref{fig:sig_sigaction}, il campo
+\var{sa\_restorer}, non previsto dallo standard, è obsoleto e non deve essere
+più usato.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct sigaction {
+    void (*sa_handler)(int);
+    void (*sa_sigaction)(int, siginfo_t *, void *);
+    sigset_t sa_mask;
+    int sa_flags;
+    void (*sa_restorer)(void);
+}
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \var{sigaction}.} 
+  \label{fig:sig_sigaction}
+\end{figure}
 
 
 
 
+\subsection{I \textit{signal set}}
+\label{sec:sig_sigset}
+
+
+\subsection{Le funzioni \func{sigpending} e \func{sigsuspend}}
+\label{sec:sig_sigpending}
 
 
 
 
-\subsection{La funzione \func{sigaction}}
-\label{sec:sig_sigaction}
 
 
 
 
 
 
@@ -1625,8 +1698,6 @@ principale, interrompendone inopportunamente l'esecuzione.
 \label{sec:sig_reentrant}
 
 
 \label{sec:sig_reentrant}
 
 
-, affrontando inoltre le varie problematiche di programmazione che si devono
-tenere presenti quando si ha a che fare con essi.