Rimaneggiata ancora la parte sullo scheduler, con ancora piu` casino.
[gapil.git] / signal.tex
index eeefd982d7f2115f4b9c100ac905a4151947e3d1..fec20a72c0d0465508faae3bda50031b4a894bc8 100644 (file)
@@ -22,9 +22,10 @@ gestione.
 \section{Introduzione}
 \label{sec:sig_intro}
 
-In questa sezione esamineremo i concetti base dei segnali, introducendo le
-caratteristiche essenziali con cui il sistema interagisce con i processi
-attraverso di essi.
+In questa sezione esamineremo i concetti generali relativi ai segnali, vedremo
+le loro caratteristiche di base, introdurremo le nozioni di fondo relative
+all'architettura del funzionamento dei segnali e alle modalità con cui il
+sistema gestisce l'interazione fra di essi ed i processi.
 
 
 \subsection{I concetti base}
@@ -80,7 +81,7 @@ gestione, in tutti i casi in cui si vuole che il manipolatore esterno resti
 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
+perduti. Si consideri il seguente segmento di codice, in cui la prima
 operazione del manipolatore è quella di reinstallare se stesso: 
 
 \footnotesize
@@ -103,7 +104,7 @@ causare il comportamento originale assegnato al segnale (in genere la
 terminazione del processo).
 
 Questa è la ragione per cui l'implementazione dei segnali secondo questa
-semantica viene chiamata \textsl{inaffidabile}, in quanto la ricezione del
+semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del
 segnale e la reinstallazione del suo manipolatore non sono operazioni
 atomiche, e sono sempre possibili delle race condition (sull'argomento vedi
 quanto detto in \secref{sec:proc_multi_prog}).
@@ -113,54 +114,48 @@ segnali quando non si vuole che arrivino; i processi possono ignorare il
 segnale, ma non è possibile istruire il sistema a non fare nulla in occasione
 di un segnale, pur mantenendo memoria del fatto che è avvenuto.
 
-Un caso classico in cui si incontra questo problema, è quello in cui si usa il
-manipolatore per settare un flag che riporta al processo l'occorrenza del
-segnale, così che questo possa prendere provvedimenti al di fuori del
-manipolatore. Si consideri il seguente segmento di codice il cui scopo sarebbe
-quello di fermare il processo fino all'occorrenza di un opportuno segnale:
-
-\footnotesize
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-int signal_flag = 0;
-main()
-{
-    int sig_handler();            /* handler function */
-    ...
-    signal(SIGINT, sig_handler);  /* establish handler */
-    ...
-    while(signal_flag == 0) {     /* while flag is zero */
-        pause();                  /* go to sleep */
-    }
-    ... 
-}
-int sig_handler() 
-{
-    signal(SIGINT, sig_handler);  /* restablish handler */
-    signal_flag = 1;              /* set flag */
-}
-\end{lstlisting}
-\normalsize
-l'idea è che quando il processo trova il flag a zero viene messo in sleep e
-verrà risvegliato solo dalla ricezione di un segnale. Il manipolatore si
-limita in questo caso a settare il flag a uno; all'uscita dal manipolatore la
-chiamata a \func{pause} è interrotta ed il processo viene risvegliato e
-riprende l'esecuzione all'istruzione successiva, ma essendo cambiato il flag
-la condizione non è più soddisfatta e il programma prosegue.
-
-Il problema con l'implementazione inaffidabile è che niente ci garantisce che
-il segnale arrivi fra la valutazione della condizione del \code{while} e la
-chiamata a \func{pause}, nel qual caso, se il segnale non viene più generato,
-il processo resterà in sleep permanentemente.
-
-% Un'altra caratteristica della implementazione inaffidabile è che le chiamate
-% di sistema non sono fatte ripartire automaticamente quando sono interrotte da
-% un segnale, per questo un programma deve controllare lo stato di uscita della
-% chiamata al sistema e ripeterla nel caso l'errore riportato da \texttt{errno}
-% sia \texttt{EINTR}.
-
-Questo ci mostra ad esempio come con la semantica inaffidabile non esista una
-modalità semplice per ottenere una operazione di pausa (cioè mandare in sleep
-un processo fino all'arrivo di un segnale).
+% Un caso classico in cui si incontra questo problema, è quello in cui si usa il
+% manipolatore per settare un flag che riporta al processo l'occorrenza del
+% segnale, così che questo possa prendere provvedimenti al di fuori del
+% manipolatore. Si consideri il seguente segmento di codice il cui scopo sarebbe
+% quello di fermare il processo fino all'occorrenza di un opportuno segnale:
+
+% \footnotesize
+% \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+% int signal_flag = 0;
+% main()
+% {
+%     int sig_handler();            /* handler function */
+%     ...
+%     signal(SIGINT, sig_handler);  /* establish handler */
+%     ...
+%     while(signal_flag == 0) {     /* while flag is zero */
+%         pause();                  /* go to sleep */
+%     }
+%     ... 
+% }
+% int sig_handler() 
+% {
+%     signal(SIGINT, sig_handler);  /* restablish handler */
+%     signal_flag = 1;              /* set flag */
+% }
+% \end{lstlisting}
+% \normalsize
+% l'idea è che quando il processo trova il flag a zero viene messo in sleep e
+% verrà risvegliato solo dalla ricezione di un segnale. Il manipolatore si
+% limita in questo caso a settare il flag a uno; all'uscita dal manipolatore la
+% chiamata a \func{pause} è interrotta ed il processo viene risvegliato e
+% riprende l'esecuzione all'istruzione successiva, ma essendo cambiato il flag
+% la condizione non è più soddisfatta e il programma prosegue.
+
+% Il problema con l'implementazione inaffidabile è che niente ci garantisce che
+% il segnale arrivi fra la valutazione della condizione del \code{while} e la
+% chiamata a \func{pause}, nel qual caso, se il segnale non viene più generato,
+% il processo resterà in sleep permanentemente.
+
+% Questo ci mostra ad esempio come con la semantica inaffidabile non esista una
+% modalità semplice per ottenere una operazione di attesa mandando in stato di
+% sleep (vedi \ref{sec:proc_sched}) un processo fino all'arrivo di un segnale.
 
 Nella semantica \textsl{affidabile} (quella utilizzata da Linux e da ogni Unix
 moderno) il manipolatore una volta installato resta attivo e non si hanno
@@ -274,9 +269,9 @@ una  delle tre possibilit
 
 Un programma può specificare queste scelte usando le due funzioni
 \func{signal} e \func{sigaction} (vedi \secref{sec:sig_signal} e
-\secref{sec:sig_sigaction}); se si è installato un manipolatore sarà
+\secref{sec:sig_sigaction}). Se si è installato un manipolatore sarà
 quest'ultimo ad essere eseguito alla notifica del segnale.  Inoltre il sistema
-fa si che mentre viene eseguito il manipolatore di un segnale, questo ultimo
+farà si che mentre viene eseguito il manipolatore di un segnale, quest'ultimo
 venga automaticamente bloccato (così si possono evitare race condition).
 
 Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
@@ -298,7 +293,6 @@ in seguito con un debugger per investigare sulla causa dell'errore.  Lo stesso
 avviene se i suddetti segnale vengono generati con una \func{kill}.
 
 
-
 \section{La classificazione dei segnali}
 \label{sec:sig_classification}
 
@@ -472,6 +466,9 @@ Questi segnali sono:
 \item[\macro{SIGFPE}] Riporta un errore aritmetico fatale. Benché il nome
   derivi da \textit{floating point exception} si applica a tutti gli errori
   aritmetici compresa la divisione per zero e l'overflow. 
+  
+  Se il manipolatore ritorna il comportamento del processo è indefinito, ed
+  ignorare questo segnale può condurre ad un loop infinito.
 
 %   Per questo segnale le cose sono complicate dal fatto che possono esserci
 %   molte diverse eccezioni che \texttt{SIGFPE} non distingue, mentre lo
@@ -487,12 +484,14 @@ Questi segnali sono:
   posto di un puntatore a funzione, o si eccede la scrittura di un vettore di
   una variabile locale, andando a corrompere lo stack. Lo stesso segnale viene
   generato in caso di overflow dello stack o di problemi nell'esecuzione di un
-  manipolatore.
+  manipolatore. Se il manipolatore ritorna il comportamento del processo è
+  indefinito.
 \item[\macro{SIGSEGV}] Il nome deriva da \textit{segment violation}, e
   significa che il programma sta cercando di leggere o scrivere in una zona di
   memoria protetta al di fuori di quella che gli è stata riservata dal
   sistema. In genere è il meccanismo della protezione della memoria che si
-  accorge dell'errore ed il kernel genera il segnale.
+  accorge dell'errore ed il kernel genera il segnale.  Se il manipolatore
+  ritorna il comportamento del processo è indefinito.
 
   È tipico ottenere questo segnale dereferenziando un puntatore nullo o non
   inizializzato leggendo al di la della fine di un vettore. 
@@ -779,7 +778,7 @@ processo alla loro occorrenza.
 
 
 \subsection{Il comportamento generale del sistema.}
-\label{sec:sig_gen_beha}
+  \label{sec:sig_gen_beha}
 
 Abbiamo già trattato in \secref{sec:sig_intro} le modalità con cui il sistema
 gestisce l'interazione fra segnali e processi, ci resta da esaminare però il
@@ -820,8 +819,8 @@ eseguire un manipolatore non comporta nessun inconveniente.
 Esistono però dei casi in cui questo non è possibile perché renderebbe
 impossibile una risposta pronta al segnale. In generale questo avviene tutte
 le volte che si ha a che fare con system call che possono bloccarsi
-indefinitamente, che per questo vengono chiamate \textsl{lente}. Un elenco
-dei casi in cui si presenta questa situazione è il seguente:
+indefinitamente, (quelle che, per questo, vengono chiamate \textsl{lente}). Un
+elenco dei casi in cui si presenta questa situazione è il seguente:
 \begin{itemize*}
 \item lettura da file che possono bloccarsi in attesa di dati non ancora
   presenti (come per certi file di dispositivo, la rete o le pipe).
@@ -925,7 +924,7 @@ tutti i segnali pendenti saranno scartati, e non verranno mai notificati.
 L'uso di \func{signal} è soggetto a problemi di compatibilità, dato che essa
 si comporta in maniera diversa per sistemi derivati da BSD o da System V. In
 questi ultimi infatti la funzione è conforme al comportamento originale dei
-primi Unix in cui il manipolatore viene disinstallato alla sua chiamata
+primi Unix in cui il manipolatore viene disinstallato alla sua chiamata,
 secondo la semantica inaffidabile; Linux seguiva questa convenzione fino alle
 \acr{libc5}. Al contrario BSD segue la semantica affidabile, non resettando il
 manipolatore e bloccando il segnale durante l'esecuzione dello stesso. Con
@@ -1045,7 +1044,7 @@ 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
-segnali di temporizzazione e \macro{SIGABORT}, per i quali sono previste
+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 è:
 \begin{prototype}{unistd.h}{unsigned int alarm(unsigned int seconds)}
@@ -1057,8 +1056,9 @@ funzioni specifiche che ne effettuino l'invio. La prima di queste 
 
 La funzione provvede un meccanismo che consente ad un processo di predisporre
 un'interruzione nel futuro, (ad esempio per effettuare una qualche operazione
-dopo un certo periodo di tempo), programmando l'emissione si un segnale di
-\macro{SIGALARM} dopo il numero di secondi specificato da \param{seconds}.
+dopo un certo periodo di tempo), programmando l'emissione di un segnale (in
+genere \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,
@@ -1086,9 +1086,10 @@ processo tre diversi timer:
 \end{itemize}
 
 Il timer usato da \func{alarm} è il \textit{clock time}, e corrisponde cioè al
-tempo reale. La funzione, pur essendo molto semplice, presenta numerosi
-limiti: non consente di usare gli altri timer, non può specificare intervalli
-con precisione maggiore del secondo e genera il segnale una sola volta.
+tempo reale. La funzione come abbiamo visto è molto semplice, ma proprio per
+questo presenta numerosi limiti: non consente di usare gli altri timer, non
+può specificare intervalli di tempo con precisione maggiore del secondo e
+genera il segnale una sola volta.
 
 Per ovviare a questi limiti Linux deriva da BSD la funzione \func{setitimer}
 che permette di usare un timer qualunque e l'invio di segnali periodici, al
@@ -1235,21 +1236,23 @@ il processo non viene terminato direttamente dal manipolatore sia la stessa
 \func{abort} a farlo al ritorno dello stesso. Inoltre, sempre seguendo lo
 standard POSIX, prima della terminazione tutti i file aperti e gli stream
 saranno chiusi ed i buffer scaricati su disco. Non verranno invece eseguite le
-funzioni registrate con \func{at\_exit} e \func{on\_exit}.
+eventuali funzioni registrate con \func{at\_exit} e \func{on\_exit}.
 
 
 \subsection{Le funzioni \func{pause} e \func{sleep}}
 \label{sec:sig_pause_sleep}
 
-Il metodo tradizionale per fare attendere ad un processo fino all'arrivo di un
-segnale è quello di usare la funzione \func{pause}, il cui prototipo è:
+Il metodo tradizionale per fare attendere\footnote{cioè di porre
+  temporanemente il processo in stato di \textit{sleep}, vedi
+  \ref{sec:proc_sched}.}  ad un processo fino all'arrivo di un segnale è
+quello di usare la funzione \func{pause}, il cui prototipo è:
 \begin{prototype}{unistd.h}{int pause(void)}
   
   Pone il processo in stato di sleep fino al ritorno di un manipolatore.
   
   \bodydesc{La funzione ritorna solo dopo che un segnale è stato ricevuto ed
-  il relativo manipolatore è ritornato, nel qual caso restituisce -1 e setta
-  \var{errno} a \macro{EINTR}.}
+    il relativo manipolatore è ritornato, nel qual caso restituisce -1 e setta
+    \var{errno} a \macro{EINTR}.}
 \end{prototype}
 
 La funzione segnala sempre una condizione di errore (il successo sarebbe
@@ -1258,10 +1261,9 @@ si vuole mettere un processo in attesa di un qualche evento specifico che non
 è sotto il suo diretto controllo (ad esempio la si può usare per far reagire
 il processo ad un segnale inviato da un altro processo).
 
-
 Se invece si vuole fare attendere un processo per un determinato intervallo di
-tempo lo standard POSIX.1 definisce la funzione \func{sleep}, il cui prototipo
-è:
+tempo nello standard POSIX.1 viene definita la funzione \func{sleep}, il cui
+prototipo è:
 \begin{prototype}{unistd.h}{unsigned int sleep(unsigned int seconds)}
   
   Pone il processo in stato di sleep per \param{seconds} secondi.
@@ -1275,14 +1277,15 @@ da un segnale. In questo caso non 
 tempo rimanente, in quanto la riattivazione del processo può avvenire in un
 qualunque momento, ma il valore restituito sarà sempre arrotondato al secondo,
 con la conseguenza che, se la successione dei segnali è particolarmente
-sfortunata, si potranno avere ritardi anche di parecchi secondi. In genere la
-scelta più sicura è quella di stabilire un termine per l'attesa, e ricalcolare
-tutte le volte il numero di secondi da aspettare.
+sfortunata e le differenze si accumulano, si potranno avere ritardi anche di
+parecchi secondi. In genere la scelta più sicura è quella di stabilire un
+termine per l'attesa, e ricalcolare tutte le volte il numero di secondi da
+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
-attraverso \func{pause} e \func{alarm} (in maniera analoga all'esempio che
-vedremo in \ref{sec:sig_example}). In tal caso mescolare chiamata di
+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 \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.
@@ -1292,7 +1295,7 @@ questo sia sotto BSD4.3 che in SUSv2 
 \func{usleep} (dove la \texttt{u} è intesa come sostituzione di $\mu$); i due
 standard hanno delle definizioni diverse, ma le \acr{glibc}
 seguono\footnote{secondo la man page almeno dalla versione 2.2.2.} seguono
-quella di SUSv2 che prevede il seguente prototipo: 
+quella di SUSv2 che prevede il seguente prototipo:
 \begin{prototype}{unistd.h}{int usleep(unsigned long usec)}
   
   Pone il processo in stato di sleep per \param{usec} microsecondi.
@@ -1302,10 +1305,10 @@ quella di SUSv2 che prevede il seguente prototipo:
 
 \end{prototype}
 
-Anche questa funzione a seconda delle implementazioni può presentare problemi
-nell'interazione con \func{alarm} e \macro{SIGALRM}, ed è pertanto deprecata
-in favore di \func{nanosleep}, definita dallo standard POSIX1.b, il cui
-prototipo è:
+Anche questa funzione, a seconda delle implementazioni, può presentare
+problemi nell'interazione con \func{alarm} e \macro{SIGALRM}. È pertanto
+deprecata in favore della funzione \func{nanosleep}, definita dallo standard
+POSIX1.b, il cui prototipo è:
 \begin{prototype}{unistd.h}{int nanosleep(const struct timespec *req, struct
     timespec *rem)}
   
@@ -1374,16 +1377,25 @@ Un semplice esempio per illustrare il funzionamento di un manipolatore di
 segnale è quello della gestione di \macro{SIGCHLD}. Abbiamo visto in
 \secref{sec:proc_termination} che una delle azioni eseguite dal kernel alla
 conclusione di un processo è quella di inviare questo segnale al
-padre;\footnote{in realtà in SRV4 eredita la semantica di System V, in cui il
+padre.\footnote{in realtà in SRV4 eredita la semantica di System V, in cui il
   segnale si chiama \macro{SIGCLD} e viene trattato in maniera speciale; in
   System V infatti se si setta esplicitamente l'azione a \macro{SIG\_IGN} il
   segnale non viene generato ed il sistema non genera zombie (lo stato di
   terminazione viene scartato senza dover chiamare una \func{wait}). L'azione
   di default è sempre quella di ignorare il segnale, ma non attiva questo
   comportamento. Linux, come BSD e POSIX, non supporta questa semantica ed usa
-  il nome di \macro{SIGCLD} come sinonimo di \macro{SIGCHLD}.} in questo caso
-tutto quello che dovrà fare il manipolatore è ricevere lo stato di
-terminazione in modo da evitare la formazione di zombie.
+  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{waitpid} per
+completare la procedura di terminazione in modo da evitare la formazione di
+zombie.
+
+In \figref{fig:sig_sigchld_handl} è mostrato il codice della nostra
+implementazione del manipolatore; se aggiungiamo al codice di
+\file{ForkTest.c} l'intallazione di questo manipolatore potremo verificare che
+ripetendo l'esempio visto in \secref{sec:proc_termination} che non si ha più
+la creazione di zombie.
 
 %  è pertanto
 % naturale usare un esempio che ci permette di concludere la trattazione della
@@ -1391,15 +1403,11 @@ terminazione in modo da evitare la formazione di zombie.
 % In questo caso si è tratterà di illustrare un esempio relativo ad un
 % manipolatore per che è previsto ritornare,
 
-In 
-
-
-
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+    \begin{lstlisting}{}
 #include <errno.h>       /* error simbol definitions */
 #include <signal.h>      /* signal handling declarations */
 #include <sys/types.h>
@@ -1421,7 +1429,7 @@ void Hand_CHLD(int sig)
             debug("child %d terminated with status %x\n", pid, status);
         }
     } while ((pid > 0) && (errno == EINTR));
-    /* restore errno value*/
+    /* restore errno value */
     errno = errno_save;
     /* return */
     return;
@@ -1429,12 +1437,47 @@ void Hand_CHLD(int sig)
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{Una implementazione sbagliata di \func{sleep}.} 
-  \label{fig:sig_timespec_def}
+  \caption{Un manipolatore per il segnale \texttt{SIGCHLD}.} 
+  \label{fig:sig_sigchld_handl}
 \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}.
+
+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
+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.
+
+Questo può essere un caso comune proprio con \texttt{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}
@@ -1453,14 +1496,16 @@ risolvere i problemi pi
 \subsection{Un esempio di problema}
 \label{sec:sig_example}
 
-Come accennato in \ref{sec:sig_pause_sleep} è possibile implementare
+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:
+semplice versione di \func{sleep} potrebbe essere la seguente quella
+illustrata in \ref{fig:sig_sleep_wrong}.
+
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+    \begin{lstlisting}{}
 unsigned int sleep(unsigned int seconds)
 {
     signandler_t prev_handler;
@@ -1488,7 +1533,7 @@ void alarm_hand(int sig) {
   \end{minipage} 
   \normalsize 
   \caption{Una implementazione sbagliata di \func{sleep}.} 
-  \label{fig:sig_timespec_def}
+  \label{fig:sig_sleep_wrong}
 \end{figure}
 
 Ma questa funzione, a parte il non gestire il caso in cui si è avuta una