Correzione ai limiti, aggiustate referenze e iniziato le funzioni per
[gapil.git] / process.tex
index 483fbb9a9bbdd10cb8b06e3b7e5398425e31dcab..4d02cbc0a461530b5660a29ed210a13ceb5da0fa 100644 (file)
@@ -23,9 +23,9 @@ programma: si possono avere pi
 ciascun processo vedrà la sua copia del codice (in realtà il kernel fa sì che
 tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi,
 variabili proprie e sarà eseguito in maniera completamente indipendente da
-tutti gli altri\footnote{questo non è del tutto vero nel caso di un programma
+tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma
   \textit{multi-thread}, ma sulla gestione dei \textit{thread} in Linux
-  torneremo più avanti}.
+  torneremo più avanti.}
 
 
 \subsection{La funzione \func{main}} 
@@ -108,7 +108,7 @@ uno stato di uscita uguale a zero, che verrebbe interpretato come un successo.
 In \file{stdlib.h} sono definite, seguendo lo standard POSIX, le due macro
 \macro{EXIT\_SUCCESS} e \macro{EXIT\_FAILURE}, da usare sempre per specificare
 lo stato di uscita di un processo. In Linux esse sono poste rispettivamente ai
-valori di tipo \type{int} 0 e 1.
+valori di tipo \ctyp{int} 0 e 1.
 
 
 \subsection{Le funzioni \func{exit} e \func{\_exit}}
@@ -253,11 +253,12 @@ esecuzione, e le varie funzioni utilizzabili per la sua gestione.
 Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli
 di basso livello dipendono spesso in maniera diretta dall'architettura
 dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è
-la cosiddetta \textsl{memoria virtuale} che consiste nell'assegnare ad ogni
-processo uno spazio virtuale di indirizzamento lineare, in cui gli indirizzi
-vanno da zero ad un qualche valore massimo\footnote{nel caso di Linux fino al
-  kernel 2.2 detto massimo era, per macchine a 32bit, di 2Gb, con il kernel
-  2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso}.
+la cosiddetta \textsl{memoria virtuale}\index{memoria virtuale} che consiste
+nell'assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare,
+in cui gli indirizzi vanno da zero ad un qualche valore massimo.\footnote{nel
+  caso di Linux fino al kernel 2.2 detto massimo era, per macchine a 32bit, di
+  2Gb, con il kernel 2.4 ed il supporto per la \textit{high-memory} il limite
+  è stato esteso.}
 
 Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è
 virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
@@ -286,15 +287,15 @@ gestione della memoria (la \textit{Memory Management Unit} del processore).
 Poiché in genere la memoria fisica è solo una piccola frazione della memoria
 virtuale, è necessario un meccanismo che permetta di trasferire le pagine che
 servono dal supporto su cui si trovano in memoria, eliminando quelle che non
-servono. Questo meccanismo è detto \textit{paging}, ed è uno dei compiti
-principali del kernel.
+servono. Questo meccanismo è detto \textsl{paginazione}\index{paginazione} (o
+\textit{paging}), ed è uno dei compiti principali del kernel.
 
 Quando un processo cerca di accedere ad una pagina che non è nella memoria
-reale, avviene quello che viene chiamato un \textit{page fault}; l'hardware di
-gestione della memoria genera un'interruzione e passa il controllo al kernel
-il quale sospende il processo e si incarica di mettere in RAM la pagina
-richiesta (effettuando tutte le operazioni necessarie per reperire lo spazio
-necessario), per poi restituire il controllo al processo.
+reale, avviene quello che viene chiamato un \textit{page fault}\index{page
+  fault}; l'hardware di gestione della memoria genera un'interruzione e passa
+il controllo al kernel il quale sospende il processo e si incarica di mettere
+in RAM la pagina richiesta (effettuando tutte le operazioni necessarie per
+reperire lo spazio necessario), per poi restituire il controllo al processo.
 
 Dal punto di vista di un processo questo meccanismo è completamente
 trasparente, e tutto avviene come se tutte le pagine fossero sempre
@@ -305,8 +306,8 @@ a tempi molto pi
 Normalmente questo è il prezzo da pagare per avere un multitasking reale, ed
 in genere il sistema è molto efficiente in questo lavoro; quando però ci siano
 esigenze specifiche di prestazioni è possibile usare delle funzioni che
-permettono di bloccare il meccanismo del paging e mantenere fisse delle pagine
-in memoria (vedi \ref{sec:proc_mem_lock}).
+permettono di bloccare il meccanismo della paginazione e mantenere fisse delle
+pagine in memoria (vedi \ref{sec:proc_mem_lock}).
 
 
 \subsection{La struttura della memoria di un processo}
@@ -318,9 +319,9 @@ tentativo di accedere ad un indirizzo non allocato 
 commette quando si è manipolato male un puntatore e genera quello che viene
 chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
 scrivere da un indirizzo per il quale non esiste un'associazione della pagina
-virtuale, il kernel risponde al relativo \textit{page fault} mandando un
-segnale \macro{SIGSEGV} al processo, che normalmente ne causa la terminazione
-immediata.
+virtuale, il kernel risponde al relativo \textit{page fault}
+mandando un segnale \macro{SIGSEGV} al processo, che normalmente ne causa la
+terminazione immediata.
 
 È pertanto importante capire come viene strutturata la memoria virtuale di un
 processo. Essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di
@@ -341,7 +342,7 @@ programma C viene suddiviso nei seguenti segmenti:
 \item Il segmento dei dati o \textit{data segment}. Contiene le variabili
   globali (cioè quelle definite al di fuori di tutte le funzioni che
   compongono il programma) e le variabili statiche (cioè quelle dichiarate con
-  l'attributo \type{static}). Di norma è diviso in due parti.
+  l'attributo \ctyp{static}). Di norma è diviso in due parti.
   
   La prima parte è il segmento dei dati inizializzati, che contiene le
   variabili il cui valore è stato assegnato esplicitamente. Ad esempio
@@ -495,13 +496,13 @@ La funzione \func{realloc} si usa invece per cambiare (in genere aumentare) la
 dimensione di un'area di memoria precedentemente allocata, la funzione vuole
 in ingresso il puntatore restituito dalla precedente chiamata ad una
 \func{malloc} (se è passato un valore \macro{NULL} allora la funzione si
-comporta come \func{malloc}\footnote{questo è vero per Linux e
+comporta come \func{malloc},\footnote{questo è vero per Linux e
   l'implementazione secondo lo standard ANSI C, ma non è vero per alcune
   vecchie implementazioni, inoltre alcune versioni delle librerie del C
   consentivano di usare \func{realloc} anche per un puntatore liberato con
   \func{free} purché non ci fossero state nel frattempo altre chiamate a
   funzioni di allocazione, questa funzionalità è totalmente deprecata e non è
-  consentita sotto Linux.}), ad esempio quando si deve far crescere la
+  consentita sotto Linux.}) ad esempio quando si deve far crescere la
 dimensione di un vettore. In questo caso se è disponibile dello spazio
 adiacente al precedente la funzione lo utilizza, altrimenti rialloca altrove
 un blocco della dimensione voluta, copiandoci automaticamente il contenuto; lo
@@ -662,10 +663,10 @@ memoria per metterle nello swap, sulla base dell'utilizzo corrente da parte
 dei vari processi.
 
 Nell'uso comune un processo non deve preoccuparsi di tutto ciò, in quanto il
-meccanismo della paginazione riporta in RAM, ed in maniera trasparente, tutte
-le pagine che gli occorrono; esistono però esigenze particolari in cui non si
-vuole che questo meccanismo si attivi. In generale i motivi per cui si possono
-avere di queste necessità sono due:
+meccanismo della paginazione\index{paginazione} riporta in RAM, ed in maniera
+trasparente, tutte le pagine che gli occorrono; esistono però esigenze
+particolari in cui non si vuole che questo meccanismo si attivi. In generale i
+motivi per cui si possono avere di queste necessità sono due:
 \begin{itemize}
 \item \textsl{La velocità}. Il processo della paginazione è trasparente solo
   se il programma in esecuzione non è sensibile al tempo che occorre a
@@ -1131,7 +1132,7 @@ ambiente; il suo prototipo 
 \end{functions}
 \noindent questa funzione elimina ogni occorrenza della variabile specificata;
 se essa non esiste non succede nulla. Non è prevista (dato che la funzione è
-\type{void}) nessuna segnalazione di errore.
+\ctyp{void}) nessuna segnalazione di errore.
 
 Per modificare o aggiungere una variabile di ambiente si possono usare sia
 \func{setenv} che \func{putenv}. La prima permette di specificare
@@ -1151,7 +1152,7 @@ invece esiste il suo valore sar
   seguendo il comportamento di BSD4.4; dato che questo può dar luogo a perdite
   di memoria e non rispetta lo standard. Il comportamento è stato modificato a
   partire dalle 2.1.2, eliminando anche, sempre in conformità a SUSv2,
-  l'attributo \type{const} dal prototipo.} \param{string} alla lista delle
+  l'attributo \ctyp{const} dal prototipo.} \param{string} alla lista delle
 variabili di ambiente; pertanto ogni cambiamento alla stringa in questione si
 riflette automaticamente sull'ambiente, e quindi si deve evitare di passare a
 questa funzione una variabile automatica (per evitare i problemi esposti in
@@ -1213,7 +1214,6 @@ informazioni a riguardo dei risultati vengono passate alla routine chiamante
 attraverso il valore di ritorno.  È buona norma seguire questa pratica anche
 nella programmazione normale.
 
-
 Talvolta però è necessario che la funzione possa restituire indietro alla
 funzione chiamante un valore relativo ad uno dei suoi parametri.  Per far
 questo si usa il cosiddetto \textit{value result argument}, si passa cioè,
@@ -1261,13 +1261,13 @@ del vettore \var{argv} passato al nuovo processo). Lo standard ISO C richiede
 inoltre che l'ultimo degli argomenti fissi sia di tipo
 \textit{self-promoting}\footnote{il linguaggio C prevede che quando si
   mescolano vari tipi di dati, alcuni di essi possano essere \textsl{promossi}
-  per compatibilità; ad esempio i tipi \type{float} vengono convertiti
-  automaticamente a \type{double} ed i \type{char} e gli \type{short} ad
-  \type{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso
+  per compatibilità; ad esempio i tipi \ctyp{float} vengono convertiti
+  automaticamente a \ctyp{double} ed i \ctyp{char} e gli \ctyp{short} ad
+  \ctyp{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso
   a sé stesso.} il che esclude array, puntatori a funzioni e interi di tipo
-\type{char} o \type{short} (con segno o meno). Una restrizione ulteriore di
+\ctyp{char} o \ctyp{short} (con segno o meno). Una restrizione ulteriore di
 alcuni compilatori è di non dichiarare l'ultimo parametro fisso come
-\type{register}.
+\ctyp{register}.
 
 Una volta dichiarata la funzione il secondo passo è accedere ai vari parametri
 quando la si va a definire. I parametri fissi infatti hanno un loro nome, ma
@@ -1340,8 +1340,8 @@ motivo \macro{va\_list} 
 direttamente ad un altra variabile dello stesso tipo. Per risolvere questo
 problema lo standard ISO C99\footnote{alcuni sistemi che non hanno questa
   macro provvedono al suo posto \macro{\_\_va\_copy} che era il nome proposto
-  in una bozza dello standard} ha previsto una macro ulteriore che permette di
-eseguire la copia di un puntatore alla lista degli argomenti:
+  in una bozza dello standard.} ha previsto una macro ulteriore che permette
+di eseguire la copia di un puntatore alla lista degli argomenti:
 \begin{prototype}{stdarg.h}{void va\_copy(va\_list dest, va\_list src)}
   Copia l'attuale valore \param{src} del puntatore alla lista degli argomenti
   su \param{dest}.
@@ -1360,9 +1360,8 @@ In Linux gli argomenti dello stesso tipo sono passati allo stesso modo, sia
 che siano fissi sia che siano opzionali (alcuni sistemi trattano diversamente
 gli opzionali), ma dato che il prototipo non può specificare il tipo degli
 argomenti opzionali, questi verranno sempre promossi, pertanto nella ricezione
-dei medesimi occorrerà tenerne conto (ad esempio un \type{char} verrà visto da
-\macro{va\_arg} come \type{int}).
-
+dei medesimi occorrerà tenerne conto (ad esempio un \ctyp{char} verrà visto da
+\macro{va\_arg} come \ctyp{int}).
 
 Uno dei problemi che si devono affrontare con le funzioni con un numero
 variabile di argomenti è che non esiste un modo generico che permetta di
@@ -1394,9 +1393,10 @@ Per questo una delle regole fondamentali della programmazione in C 
 all'uscita di una funzione non deve restare nessun riferimento alle variabili
 locali; qualora sia necessario utilizzare variabili che possano essere viste
 anche dalla funzione chiamante queste devono essere allocate esplicitamente, o
-in maniera statica (usando variabili di tipo \type{static} o \type{extern}), o
+in maniera statica (usando variabili di tipo \ctyp{static} o \ctyp{extern}), o
 dinamicamente con una delle funzioni della famiglia \func{malloc}.
 
+
 \subsection{Il controllo di flusso non locale}
 \label{sec:proc_longjmp}
 
@@ -1405,46 +1405,119 @@ varie istruzioni del linguaggio C; fra queste la pi
 \code{goto}, che viene deprecato in favore dei costrutti della programmazione
 strutturata, che rendono il codice più leggibile e mantenibile . Esiste però
 un caso in cui l'uso di questa istruzione porta all'implementazione più
-efficiente e chiara anche dal punto di vista della struttura del programma,
+efficiente e chiara anche dal punto di vista della struttura del programma:
 quello dell'uscita in caso di errore.
 
 Il C però non consente di effettuare un salto ad una label definita in
-un'altra funzione, per cui se l'errore avviene in funzioni profondamente
-annidate occorre usare quello che viene chiamato un salto \textsl{non-locale};
-questo viene fatto usando salvando il contesto dello stack nel punto in cui si
-vuole tornare in caso di errore, e ripristinandolo quando l'occorrenza capita.
-
-La funzione che permette di salvare il contesto dello stack è \func{setjmp},
-il cui prototipo è:
-
+un'altra funzione, per cui se l'errore avviene in una funzione e la sua
+gestione ordinaria è in un'altra occorre usare quello che viene chiamato un
+\textsl{salto non-locale}.  Il caso classico in cui si ha questa necessità,
+citato sia da \cite{APUE} che da da \cite{glibc}, è quello di un programma nel
+cui corpo principale in cui viene letto un input del quale viene eseguita
+attraverso una serie di funzioni di analisi una scansione dei contenuti da cui
+ottenere le indicazioni per l'esecuzione di opportune operazioni.
+
+Dato che l'analisi può risultare molto complessa, ed opportunamente suddivisa
+in fasi diverse, la rilevazione di un errore nell'input può accadere
+all'interno di funzioni profondamente annidate l'una nell'altra. In questo
+caso si dovrebbe per ciascuna fase dover gestire tutta la casistica del
+passaggio all'indietro di tutti gli errori rilevabili dalle funzioni usate
+nelle fasi successive, mentre sarebbe molto più comodo poter tornare
+direttamente al ciclo di lettura principale, scartando l'input come
+errato.\footnote{a meno che, come precisa \cite{glibc}, alla chiusura di
+  ciascuna fase non siano associate operazioni di pulizia specifiche (come
+  deallocazioni, chiusure di file, ecc.), che non potrebbero essere eseguite
+  con un salto non-locale.}
+
+Tutto ciò può essere realizzato salvando il contesto dello stack nel punto in
+cui si vuole tornare in caso di errore, e ripristinandolo quando l'occorrenza
+capita. La funzione che permette di salvare il contesto dello stack è
+\func{setjmp}, il cui prototipo è:
 \begin{functions}
   \headdecl{setjmp.h}
   \funcdecl{void setjmp(jmp\_buf env)}
   
   Salva il contesto dello stack in \param{env} per un successivo uso da parte
-  di \func{longjmp}. Il contesto viene invalidato se la routine che ha
-  chiamato \func{setjmp} ritorna.
-  
+  di \func{longjmp}. 
+
   \bodydesc{La funzione ritorna zero quando è chiamata direttamente e un
     valore diverso da zero quando ritorna da una chiamata di \func{longjmp}
     che usa il contesto salvato in precedenza.}
 \end{functions}
 
-
-Per poter effettuare un salto non locale si usa la funzione \func{longjmp}; il
-suo prototipo è:
+Quando si esegue la funzione il contesto viene salvato in appositi oggetti (di
+tipo \type{jmp\_buf}), passati come primo argomento alla funzione, in genere
+questi vengono definiti come variabili globali in modo da poter essere visti
+in tutte le funzioni del programma.
+
+Quando viene eseguita direttamente la funzione ritorna sempre zero, un valore
+diverso da zero viene restituito solo quando il ritorno è dovuto ad una
+chiamata di \func{longjmp} in un'altra parte del programma. Si tenga conto che
+il contesto salvato in \param{env} viene invalidato se la routine che ha
+chiamato \func{setjmp} ritorna, nel qual caso l'uso di \func{longjmp} può
+comportare conseguenze imprevedibili (e di norma fatali per il processo).
+  
+Come accennato per effettuare un salto non-locale ad un punto precedentemente
+stabilito con \func{setjmp} si usa la funzione \func{longjmp}; il suo
+prototipo è:
 \begin{functions}
   \headdecl{setjmp.h}
   \funcdecl{void longjmp(jmp\_buf env, int val)}
   
-  Ripristina il contesto dello stack salvato dall'ultima chiamata di
-  \func{setjmp} con l'argomento \param{env}. Il programma prosegue dal ritorno
-  di \func{setjmp} con un valore \param{val}. Il valore di \param{val} deve
-  essere diverso da zero, se viene specificato 0 sarà usato 1 al suo posto.
-
+  Ripristina il contesto dello stack salvato nell'ultima chiamata di
+  \func{setjmp} con l'argomento \param{env}.
+  
   \bodydesc{La funzione non ritorna.}
 \end{functions}
 
+Dopo l'esecuzione della funzione programma prosegue dal codice successivo al
+ritorno della \func{setjmp} con cui si era salvato \param{env}, che restituirà
+il valore \param{val} invece di zero.  Il valore di \param{val} specificato
+nella chiamata deve essere diverso da zero, se si è specificato 0 sarà
+comunque restituito 1 al suo posto.
+
+In sostanza un \func{longjmp} è analogo ad un \code{return}, solo che invece
+di ritornare alla riga successiva della funzione chiamante, il programma
+ritorna alla posizione della relativa \func{setjmp}, ed il ritorno può essere
+effettuato anche attraverso diversi livelli di funzioni annidate.
+
+L'implementazione di queste funzioni comporta alcune restrizioni dato che esse
+interagiscono direttamente con la gestione dello stack ed il funzionamento del
+compilatore stesso. In particolare \func{setjmp} è implementata con una macro,
+pertanto non si può cercare di ottenerne l'indirizzo, ed inoltre delle
+chiamate a questa funzione sono sicure solo in uno dei seguenti casi:
+\begin{itemize}
+\item come espressione di controllo in un comando condizionale, di selezione
+  o di iterazione (come \code{if}, \code{switch} o \code{while}).
+\item come operando per un operatore di uguaglianza o confronto in una
+  espressione di controllo di un comando condizionale, di selezione o di
+  iterazione.
+\item come operando per l'operatore di negazione (\code{!}) in una espressione
+  di controllo di un comando condizionale, di selezione o di iterazione.
+\item come espressione a sé stante.
+\end{itemize}
+
+In generale, dato che l'unica differenza fra la chiamata diretta e quella
+ottenuta da un \func{longjmp}, è il valore di ritorno di \func{setjmp}, essa è
+usualmente chiamata all'interno di un comando \code{if}. 
+
+Uno dei punti critici dei salti non-locali è quello del valore delle
+variabili, ed in particolare quello delle variabili automatiche della funzione
+a cui si ritorna. In generale le variabili globali e statiche mantengono i
+valori che avevano al momento della chiamata di \func{longjmp}, ma quelli
+delle variabili automatiche (o di quelle dichiarate \code{register}) sono in
+genere indeterminati.
+
+Quello che succede infatti è che i valori delle variabili che sono tenute in
+memoria manterranno il valore avuto al momento della chiamata di
+\func{longjmp}, mentre quelli tenuti nei registri del processore (che nella
+chiamata ad un'altra funzioni vengono salvati nel contesto nello stack)
+torneranno al valore avuto al momento della chiamata di \func{setjmp}; per
+questo quando si vuole avere un comportamento coerente si può bloccare
+l'ottimizzazione che porta le variabili nei registri dichiarandole tutte come
+\code{volatile}.
+
+
 
 %%% Local Variables: 
 %%% mode: latex