Rinominati app_a e app_b
[gapil.git] / process.tex
index 84cd0fef33faac87260763e2aa09032b4967e4ca..e663713f93584f9029a0cc657cbee66cd7bed344 100644 (file)
@@ -29,7 +29,7 @@ Anche quando all'interno di un programma possono essere presenti pi
 \textsl{filoni} di esecuzione (i cosiddetti \textit{thread}), o questo possa
 essere composto da moduli multipli completamente separati, quando questo sarà
 posto in esecuzione esso apparirà al sistema come un solo processo (il
-discorso dei \textit{thread} comunque in linux necessita di una trattazione a
+discorso dei \textit{thread} comunque in Linux necessita di una trattazione a
 parte per la peculiarità dell'implementazione).
 
 \section{La funzione \texttt{main}} 
@@ -40,7 +40,7 @@ avvio, usando il programma \texttt{ld-linux.so}, 
 carica le librerie condivise che servono al programma, effettua il link
 dinamico del codice e poi alla fine lo esegue. Infatti, a meno di non aver
 specificato il flag \texttt{-static} durante la compilazione, tutti i
-programmi in linux sono incompleti e necessitano di essere linkati alle
+programmi in Linux sono incompleti e necessitano di essere linkati alle
 librerie condivise quando vengono avviati.  La procedura è controllata da
 alcune variabili di ambiente e dal contenuto di \texttt{/etc/ld.so.conf}, i
 dettagli sono riportati nella man page di \texttt{ld.so}.
@@ -50,18 +50,18 @@ sta al programmatore chiamare cos
 si suppone iniziale l'esecuzione; in ogni caso senza questa funzione lo stesso
 linker darebbe luogo ad errori.
 
-Lo stadard ISO C specifica che la funzione \texttt{main} può o non avere
+Lo standard ISO C specifica che la funzione \texttt{main} può o non avere
 argomenti o prendere due argomenti che rappresentano gli argomenti passati da
 linea di comando, in sostanza un prototipo che va sempre bene è il seguente:
-\begin{verbatim}
+\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
      int main (int argc, char *argv[])
-\end{verbatim}
+\end{lstlisting}
 
 In realtà nei sistemi unix esiste un'altro modo per definire la funzione
 \texttt{main}, che prevede la presenza di un terzo parametro, \texttt{char
-  *envp[]}, che fornisce l'\textsl{ambiente} (vedi \secref{proc_environ}) del
-programma; questa forma però non è prevista dallo standard POSIX.1 per cui se
-si vogliono scrivere programmi portabili è meglio evitarla.
+  *envp[]}, che fornisce l'\textsl{ambiente} (vedi \secref{sec:proc_environ})
+del programma; questa forma però non è prevista dallo standard POSIX.1 per cui
+se si vogliono scrivere programmi portabili è meglio evitarla.
 
 
 \subsection{Come chiudere un programma}
@@ -77,7 +77,7 @@ che passa il controllo direttamente al kernel.
 Oltre alla conclusione ``normale'' esiste anche la possibilità di una
 conclusione ``anomala'' del programma a causa di segnali o della chiamata alla
 funzione \texttt{abort} (che comunque genera un segnale che termina il
-programma); torneremo su questo in \secref{sec:sig_abort}.
+programma); torneremo su questo in \secref{sec:sig_prog_error}.
 
 Il valore di ritorno della funzione main, o quello usato nelle chiamate ad
 \texttt{exit} e \texttt{\_exit}, viene chiamato \textit{exit status} e passato
@@ -96,7 +96,7 @@ la fine della funzione \texttt{main} senza ritornare esplicitamente si ha un
 valore di uscita indefinito, è pertanto consigliabile di concludere sempre in
 maniera esplicita detta funzione.
 
-Una altra convenzione riserva i valori da 128 in sù per usi speciali, ad
+Una altra convenzione riserva i valori da 128 in su per usi speciali, ad
 esempio 128 viene usato per indicare l'incapacità di eseguire un altro
 programma in un sottoprocesso. Benché anche questa convenzione non sia
 universalmente seguita è una buona idea tenerne conto.
@@ -107,7 +107,7 @@ una shell non si cura di tutto questo e comunque il valore dello stato di
 uscita è sempre troncato ad 8 bit, per cui si potrebbe incorrere nel caso in
 cui l'errore 256, diventando zero, verrebbe interpretato come un successo. In
 \texttt{stdlib.h} sono definite due macro \texttt{EXIT\_SUCCESS} e
-\texttt{EXIT\_FAILURE}, che in linux sono poste rispettivamente ai valori 0 e
+\texttt{EXIT\_FAILURE}, che in Linux sono poste rispettivamente ai valori 0 e
 1 (di tipo \texttt{int}), seguendo lo standard POSIX.
 
 Infine occorre distinguere fra lo stato di uscita di un programma
@@ -116,7 +116,7 @@ Infine occorre distinguere fra lo stato di uscita di un programma
 possibile un processo possa essere terminato (da un segnale) prima che il
 programma in esecuzione si sia concluso. In caso di conclusione normale del
 programma però lo stato di uscita diventa parte dello stato di conclusione del
-processo (vedi \secref{sec:prochand_XXX}).
+processo (vedi \secref{sec:prochand_xxx}).
 
 
 \subsection{Le funzioni \texttt{exit} e \texttt{\_exit}}
@@ -155,7 +155,7 @@ La funzione chiude tutti i file descriptor appartenenti al processo (sui tenga
 presente che questo non comporta il salvataggio dei dati bufferizzati degli
 stream), fa si che ogni figlio del processo sia ereditato da \texttt{init}
 (vedi \secref{cha:process_handling}), manda un segnale \texttt{SIGCHLD} al
-processo padre (vedi \ref{sec:sig_sigchild}) ed infine ritorna lo stato di
+processo padre (vedi \ref{sec:sig_job_control}) ed infine ritorna lo stato di
 uscita specificato in \texttt{status} che può essere raccolto usando la
 funzione \texttt{wait} (vedi \secref{sec:prochand_wait}).
 
@@ -224,7 +224,7 @@ attraveso una delle funzioni \texttt{exec} che vedremo in
 
 Allo stesso modo l'unico modo in cui un programma può concludere
 volontariamente la sua esecuzione è attraverso una chiamata alla system call
-\texttt{\_exec} sia esplicitamnte o che in maniera indiretta attraverso l'uso
+\texttt{\_exec} sia esplicitamente o che in maniera indiretta attraverso l'uso
 di \texttt{exit} o il ritorno della funzione \texttt{main}.
 
 Lo schema delle modalità con cui si avvia e conclude normalmente un programma
@@ -248,7 +248,7 @@ attraverso l'uso di un segnale (modalit
 
 Una delle risorse base che ciascun processo ha a disposizione è la memoria, ed
 uno degli aspetti più complessi di un sistema unix (ed in particolar modo di
-linux) è appunto la gestione della memoria. Qui ci occuperemo però di come la
+Linux) è appunto la gestione della memoria. Qui ci occuperemo però di come la
 memoria viene vista dal punto di vista di un programma in esecuzione in un
 processo.
 
@@ -258,14 +258,14 @@ processo.
 
 Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli
 di basso livello dipendono in maniera diretta dall'architettura
-dell'hardware), ma quello più tipico, usato da unix (e da linux) è quello di
+dell'hardware), ma quello più tipico, usato da unix (e da Linux) è quello di
 assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare in
 cui gli indirizzi vanno da zero ad un qualche valore massimo (nel caso di
-linux fino al kernel 2.2 detto massimo era per macchine a 32bit di 2Gb, con il
+Linux fino al kernel 2.2 detto massimo era per macchine a 32bit di 2Gb, con il
 kernel 2.4 il limite è stato esteso).
 
 Come accennato nell'introduzione questo spazio di indirizzi è virtuale e non
-corrisponde all'effettiva posizione dei dati nella ram del computer; in genere
+corrisponde all'effettiva posizione dei dati nella RAM del computer; in genere
 detto spazio non è neanche continuo (cioè non tutti gli indirizzi sono
 utilizzabili e/o utilizzati).
 
@@ -273,13 +273,13 @@ La memoria virtuale viene divisa in pagine (che ad esempio sono di 4kb su
 macchine a 32 bit e 8kb sulle alpha, valori strettamente connessi all'hardware
 di gestione della memoria) di dimensione fissa, e ciascuna pagina della
 memoria virtuale è associata ad un supporto che può essere una pagina di
-memoria reale o ad un dipositivo di stoccaggio secondario (in genere lo spazio
+memoria reale o ad un dispositivo di stoccaggio secondario (in genere lo spazio
 disco riservato alla swap, o i file che contengono il codice).
 
 Lo stesso pezzo di memoria reale (o di spazio disco) può fare da supporto a
 diverse pagine di memoria virtuale appartenenti a processi diversi (come
 accade in genere per le pagine che contengono il codice delle librerie
-condivise). Ad esempio il codice della fuzione \texttt{printf} starà su una
+condivise). Ad esempio il codice della funzione \texttt{printf} starà su una
 sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria
 virtuale di tutti i processi hanno detta funzione nel loro codice. 
 
@@ -296,7 +296,7 @@ Quando un processo cerca di accedere ad una pagina che non 
 reale avviene quello che viene chiamato un \textit{page fault}, l'hardware di
 gestione della memoria (la MMU del processore) genera una 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
+in RAM la pagina richiesta (effettuando tutte le operazioni necessarie per
 reperire lo spazio necessario), per poi restituire il controllo al
 processo. 
 
@@ -304,7 +304,7 @@ Dal punto di vista di un processo questo meccanismo 
 trasparente e tutto avviene come se tutte le pagine fossero sempre disponibili
 in memoria.  L'unica differenza avvertibile è quella dei tempi di esecuzione,
 che passano dai pochi nanosecondi necessari per l'accesso a tempi molto più
-lunghi, dovuti all'intervento del kernel. Normalemente questo è il prezzo da
+lunghi, dovuti all'intervento del kernel. 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
@@ -321,47 +321,47 @@ 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}, si tenta cioè di leggere e scrivere
 da un indirizzo per il quale non esiste una associazione della pagina virtuale
-ed il kernel riponde al relativo \textit{page fault} mandando un segnale
+ed il kernel risponde al relativo \textit{page fault} mandando un segnale
 \texttt{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
-indirizzi virtuali ai quali il processo può accedere. Storicamente un
+indirizzi virtuali ai quali il processo può accedere. Solitamente un
 programma C viene suddiviso nei seguenti segmenti:
 
 \begin{enumerate}
 \item Il segmento di testo (\textit{text segment}). Contiene il codice
-  macchina del programma e le costanti statiche. Normalente viene condiviso
+  macchina del programma e le costanti statiche. Normalmente viene condiviso
   così che più processi (anche diversi nel caso di librerie) possano
-  utilizzarlo e marcato in sola lettura per evitare sovrascritture accidentali
-  (o maliziose) che ne modifichino le istruzioni. 
+  utilizzarlo e viene marcato in sola lettura per evitare sovrascritture
+  accidentali (o maliziose) che ne modifichino le istruzioni.
   
   Viene allocato da \texttt{exec} all'avvio del programma e resta invariato
   per tutto il tempo dell'esecuzione.
   
-\item Il segmento dei dati (\textit{data segment}). Contiene le varibili
+\item Il segmento dei dati (\textit{data segment}). Contiene le variabili
   globali (cioè quelle definite al di fuori di tutte le funzioni). Di norma è
   diviso in due parti.
   
-  La prima è il segmento dei dati inizializzati, che contiene le variabili
-  globali il cui valore è stato assegnato esplicitamente. Ad esempio se si
-  definisce:
-\begin{verbatim}
+  La prima parte è il segmento dei dati inizializzati, che contiene le
+  variabili globali il cui valore è stato assegnato esplicitamente. Ad esempio
+  se si definisce:
+\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
     double pi = 3.14;
-\end{verbatim}
+\end{lstlisting}
   questo valore sarà immagazzinato in questo segmento. La memoria di questo
   segmento viene preallocato dalla \texttt{exec} e inizializzata ai valori
   specificati.
   
-  La seconda è il segmento dei dati non inizializzati, che contiene le
+  La seconda parte è il segmento dei dati non inizializzati, che contiene le
   variabili globali il cui valore è stato non è assegnato esplicitamente. Ad
   esempio se si definisce:
-\begin{verbatim}
+\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
     int vect[100];
-\end{verbatim}
+\end{lstlisting}
   questo valore sarà immagazzinato in questo segmento. Anch'esso viene
-  allocato all'avvio, e tutte le varibili vengono inizializzate a
+  allocato all'avvio, e tutte le variabili vengono inizializzate a
   zero (ed i puntatori a \texttt{NULL}). 
   
   Storicamente questo segmento viene chiamato BBS (da \textit{block started by
@@ -388,7 +388,7 @@ programma C viene suddiviso nei seguenti segmenti:
 
 \begin{figure}[htb]
   \centering
-  
+  \includegraphics[width=5cm]{img/memory_layout.eps}
   \caption{Disposizione tipica dei segmenti di memoria di un processo}
   \label{fig:proc_mem_layout}
 \end{figure}
@@ -400,21 +400,301 @@ salvato sul file, in quanto viene inizializzato a zero al caricamento del
 programma.
 
 
-\subsection{La librerie condivise}
-\label{sec:proc_mem_shlib}
+\subsection{Allocazione della memoria per i programmi C}
+\label{sec:proc_mem_alloc}
 
+Il C supporta due tipi di allocazione della memoria, l'allocazione statica è
+quella in cui vanno le variabili globali e le variabili statiche (e viene
+effettuata nel segmento dei dati), lo spazio per queste variabili viene
+allocati all'avvio del programma (come parte delle operazioni svolte da
+\texttt{exec}) e non viene liberato fino alla sua conclusione.
+
+L'allocazione automatica è quella che avviene per le cosiddette variabili
+automatiche, cioè gli argomenti delle funzioni o le variabili locali. Lo
+spazio per queste variabili viene allocato nello stack quando viene eseguito
+comando di invocazione della funzione e liberato quando si esce dalla
+medesima.
+
+Esiste però un terzo tipo di allocazione, che non è prevista dal linguaggio C,
+che è l'allocazione dinamica della memoria, necessaria quando il quantitativo
+di memoria che serve è determinabile solo in corso di esecuzione del
+programma. 
+
+Il C non consente di usare variabili allocate dinamicamente, non è possibile
+cioè definire in fase di programmazione una variabile le cui dimensioni
+possano essere modificate durante l'esecuzione del programma; però le librerie
+del C forniscono una serie opportuna di funzioni per permettere l'allocazione
+dinamica di spazio in memoria (in genere nello heap, usando la system call
+\texttt{sbrk}), solo che a questo punto detto spazio sarà accessibile solo in
+maniera indiretta attraverso dei puntatori.
+
+
+\subsection{Le funzioni \texttt{malloc}, \texttt{calloc}, \texttt{realloc} e
+  \texttt{free}}  
+\label{sec:proc_mem_malloc}
+
+Le funzioni previste dallo standard ANSI C per la gestione della memoria sono
+quattro, i prototipi sono i seguenti:
+\begin{functions}
+\headdecl{stdlib.h}
+\funcdecl{void *calloc(size\_t size)}
+  Alloca \texttt{size} bytes nello heap. La memoria viene inizializzata a 0.
+  
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  di successo e \texttt{NULL} in caso di fallimento, nel qual caso
+  \texttt{errno} viene settata a \texttt{ENOMEM}.
+\funcdecl{void *malloc(size\_t size)}
+  Alloca \texttt{size} bytes nello heap. La memoria non viene inizializzata.
+
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  di successo e \texttt{NULL} in caso di fallimento, nel qual caso
+  \texttt{errno} viene settata a \texttt{ENOMEM}.
+\funcdecl{void *realloc(void *ptr, size\_t size)}
+  Cambia la dimensione del blocco allocato all'indirizzo \texttt{ptr}
+  portandola a \texttt{size}.
+
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  di successo e \texttt{NULL} in caso di fallimento, nel qual caso
+  \texttt{errno} viene settata a \texttt{ENOMEM}.
+\funcdecl{void free(void *ptr)}
+  Disalloca lo spazio di memoria puntato da \texttt{ptr}.
+
+  La funzione non ritorna nulla.
+\end{functions}
+Il puntatore che le funzioni di allocazione ritornano è garantito essere
+sempre correttamente allineato per tutti i tipi di dati; ad esempio sulle
+macchine a 32 bit in genere è allineato a multipli di 4 bytes e sulle macchine
+a 64 bit a multipli di 8 bytes. 
+
+In genere su usano le funzioni \texttt{malloc} e \texttt{calloc} per allocare
+dinamicamente la memoria necessaria al programma, siccome i puntatori
+ritornati sono di tipo generico non è necessario effettuare un cast per
+assegnarli a puntatori al tipo di variabile per la quale si effettua la
+allocazione.
+
+La memoria allocata dinamicamente deve essere esplicitamente rilasciata usando
+\texttt{free}\footnote{le glibc provvedono anche una funzione \texttt{cfree}
+  defininita per compatibilità con SunOS, che è deprecata} una volta che non
+sia più necessaria. Questa funzione vuole come parametro un puntatore
+restituito da una precedente chiamata a una qualunque delle funzioni di
+allocazione e che non sia già stato liberato da un'altra chiamata a
+\texttt{free}, in caso contrario il comportamento della funzione è indefinito.
+
+La funzione \texttt{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
+\texttt{malloc} (se è passato un valore \texttt{NULL} allora la funzione si
+comporta come \texttt{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 \texttt{realloc} anche per un puntatore liberato con
+  \texttt{free} purché non ci fossero state altre chiamate a funzioni di
+  allocazione, questa funzionalità è totalmente deprecata e non è 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 utilzza, altrimenti rialloca altrove un blocco della dimensione
+voluta copiandoci automaticamente il contenuto, lo spazio in più non viene
+inizializzato. 
+
+Il fatto che il blocco di memoria restituito da \func{realloc} possa
+cambiare comporta che si deve sempre riassegnare al puntatore passato per il
+ridimensionamento il valore di ritorno della funzione, e che non ci devono
+essere altri puntatori che puntino all'interno di un'area che si vuole
+ridimensionare.
+
+Uno degli errori più comuni (specie se si ha a che fare con array di
+puntatori) è infatti quello di chiamare \texttt{free} più di una volta sullo
+stesso puntatore; per evitare questo problema una soluzione di ripiego è
+quella di assegnare sempre a \texttt{NULL} ogni puntatore liberato con
+\texttt{free}, dato che, quando il parametro è un puntatore nullo,
+\texttt{free} non esegue nessuna operazione. 
+
+Linux e le glibc hanno una implementazione delle routine di allocazione che è
+controllabile dall'utente attraverso alcune variabili di ambiente, in
+particolare diventa possibile tracciare questo tipo di errori usando la
+variabile \texttt{MALLOC\_CHECK\_} che quando viene settata mette in uso una
+versione meno efficiente delle funzioni, che però è più tollerante nei
+confronti di piccoli errori come quello di chiamate doppie a \texttt{free}; in
+pparticolare se la variabile è posta a zero gli errori vengono ignorati, se è
+posta ad 1 viene stampato un avviso sullo standard error e se 
+
+Il problema più comune e più difficile da tracciare che si incontra con
+l'allocazione della memoria è però quando la memoria non più utilizzata non
+viene opportunamente liberata (quello che in inglese viene chiamato
+\textit{memory-leak}, traducibile come \textsl{perdita di memoria}).
+
+Un caso tipico è quando l'allocazione viene fatta da una subroutine per un uso
+locale, ma la memoria non viene liberata una volta usata; chiamate ripetute
+alla stessa suubroutine causeranno a lungo andare un esaurimento della memoria
+disponibile, con un conseguente crash dell'applicazione che può avvenire in
+qualunque momento senza nessuna relazione con la subroutine che contiene
+l'errore. 
+
+Per questo motivo l'implementazione delle routine di allocazione delle glibc
+mette a disposizione una serie di funzionalità (su cui torneremo in
+\secref{sec:xxx_advanced}) che permettono di tracciare le allocazioni e
+le disallocazione, e definisce anche una serie di possibili agganci che
+permettono di sostituire alle funzioni di libreria una propria versione (che
+può essere più o meno specializzata per il debugging).
+
+
+\subsection{La funzione \texttt{alloca}}  
+\label{sec:proc_mem_alloca}
+
+Una alternativa possibile all'uso di \texttt{malloc}, che non soffre del tipo
+di problemi di memomry leak descritti in precedenza è la funzione
+\texttt{alloca} che invece che allocare la memoria nello heap usa lo il
+segmento di stack della funzione corrente. La sintassi è identica:
+\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
+  Alloca \texttt{size} bytes nel segmento di stack della funzione chiamante.
+  La memoria non viene inizializzata.
+
+  La funzione restituisce il puntatore alla zona di memoria allocata in caso
+  di successo e \texttt{NULL} in caso di fallimento, nel qual caso
+  \texttt{errno} viene settata a \texttt{ENOMEM}.
+\end{prototype}
+ma in questo caso non è più necessario liberare la memoria in quanto questa
+viene rilasciata automaticamente al ritorno della funzione.
+
+Come è evidente questa funzione ha molti vantaggi, e permette di evitare i
+problemi di memory leak non essendo più necessaria la deallocazione esplicita;
+una delle ragioni principali per usarla è però che funziona anche quando si
+usa \func{longjump} per uscire con un salto non locale da una funzione (vedi
+\secref{sec:proc_longjmp}),
+
+Un altro vantaggio e che in Linux la funzione è molto veloce e non viene
+sprecato spazio, infatti non è necessario gestire un pool di memoria da
+riservare e si evitano anche problemi di frammentazione.
+
+Gli svantaggi sono che la funzione non è disponibile su tutti gli unix quando
+non è possibile aumentare le dimensioni dello stack una volta chiamata una
+funzione e quindi l'uso limita la portabilità dei programmi, inoltre se si
+cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma un
+segnale di \textit{segmentation violation} analogo a quello che si avrebbe da
+una ricorsione infinita.
+
+Inoltre non è chiaramente possibile usare questa funzione per allocare memoria
+che deve poi essere usata anche al di fuori della funzione in cui questa viene
+chiamata, in quanto all'uscita dalla funzione lo spazio allocato diventerebbe
+libero, e potrebbe essere sovrascritto all'invocazione di nuove funzioni con
+conseguenze imprevedibili. 
+
+Questo è lo stesso problema potenziale che si può avere con le variabili
+automatiche; un errore comune infatti è quello di restituire al chiamante un
+puntatore ad una di queste variabili, che sarà automaticamente distrutta
+all'uscita della funzione, con gli stessi problemi appena citati per
+\func{alloca}.
+
+\subsection{Le funzioni \texttt{brk} e \texttt{sbrk}}  
+\label{sec:proc_mem_sbrk}
+
+L'uso di queste funzioni è necessario solo quando si voglia accedere alle
+analoghe system call a cui fanno da interfaccia (ad esempio per implementare
+una propria versione di \texttt{malloc}. Le  funzione sono:
+\begin{prototype}{unistd.h}{int *brk(void end\_data\_segment)}
+  Sposta la fine del segmento dei dati all'indirizzo specificato da
+  \texttt{end\_data\_segment}.
+  
+  La funzione restituisce 0 in caso di successo e -1 in caso di fallimento,
+  nel qual caso \texttt{errno} viene settata a \texttt{ENOMEM}.
+\end{prototype}
+\begin{prototype}{unistd.h}{int *sbrk(ptrdiff\_t increment)}
+  Incrementa lo spazio dati di un programma di \texttt{increment}. Un valore
+  zero restituisce l'attuale posizione della fine del segmento dati.
+  
+  La funzione restituisce il puntatore all'inzio della nuova zona di memoria
+  allocata in caso di successo e \texttt{NULL} in caso di fallimento, nel qual
+  caso \texttt{errno} viene settata a \texttt{ENOMEM}.
+\end{prototype}
 
+Queste funzioni sono state deliberatamente escluse dallo standard POSIX.1 e
+per i programmi normali è opportuno usare le funzioni di allocazione standard
+descritte in precedenza, che sono costruite su di esse.  In genere si usa
+\texttt{sbrk} con un valore zero per ottenere l'attuale posizione della fine
+del segmento dati. 
 
 
-\subsection{Allocazione e disallocazione della memoria}
-\label{sec:proc_mem_alloc}
+% \subsection{La personalizzazione delle funzioni di allocazione} 
+% \label{sec:proc_mem_malloc_custom}
+
+
+\subsection{Il controllo della memoria virtuale}  
+\label{sec:proc_mem_lock}
+
+Come spiegato in \secref{sec:proc_mem_gen} il kernel gestisce la memoria in
+maniera trasparente ai processi, decidendo quando rimuovere pagine dalla
+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 il meccanismo dello \textit{swapping}, in generale i motivi per cui
+si possono avere queste necessità sono sostanzialmente due:
+\begin{itemize}
+\item La velocità. Il processo della paginazione è trasparente solo se il
+  programma in esecuzione se non è sensibile al tempo che occorre a riportare
+  la pagina in memoria; per questo motivi processi critici che hanno esigenze
+  di tempo reale o tolleranze critiche nella risposte (ad esempio processi che
+  trattano campionamenti sonori) possono non essere in grado di sopportare
+  le variazioni della velocità di accesso dovuta alla paginazione.
+
+  In certi casi poi un programmatore può conoscere meglio dell'algoritmo di
+  allocazione delle pagine le esigenze specifiche del suo programma e decidere
+  quali pagine di memoria è opportuno che restino in memoria per un aumento
+  delle prestazioni. In genere queste sono esigenze particolari e richiedono
+  anche un aumento delle priorità in esecuzione (vedi \secref{sec:xxx_xxx}).
+  
+\item La sicurezza. Se si tengono password o chiavi in memoria queste possono
+  essere portate su disco dal meccanismo della paginazione, questo rende più
+  lungo il periodo di tempo in cui i segreti sono presenti in chiaro, e
+  complessa la loro cancellazione (in genere è possibile cancellare della ram
+  ma altrettanto non vale per il disco su cui la pagina contenente i segreti
+  può essere stata salvata). Per questo motivo programmi di crittografia
+  richiedono il blocco di alcune pagine di memoria.
+\end{itemize}
+
+Il meccanismo che previene la paginazione di parte della memoria virtuale di
+un processo è chiamato \textit{memory locking} (blocco della memoria), il
+blocco è sempre associato alle pagine della memoria virtuale del processo, non
+con il segmento reale di ram su cui essa viene mantenuta.
+
+La regola è che se un segmento di ram fa da supporto ad almeno una pagina
+bloccata allora esso viene escluso dal meccanismo della paginazione. I blocchi
+non si accumulano, se si blocca due volte la stessa pagina non è necessario
+sbloccarla due volte, una pagina o è bloccata o no.
 
+Il blocco di memoria persiste fintanto che il processo che lo detiene la
+memoria bloccata non la sblocca. Chiaramente la terminazione del processo
+comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di
+tutti i blocchi di memoria.
 
+I memory lock non sono ereditati dai processi figli\footnote{ma siccome Linux
+  usa il copy on write gli indirizzi virtuali del figlio sono mantenuti sullo
+  stesso segmento di ram del padre, quindi usufruiscono dei memory lock di
+  questo}. Siccome la presenza di memory lock ha un impatto sugli altri
+processi solo root ha la capacità di bloccare una pagina, ogni processo può
+però sbloccare le sue pagine. Il sistema pone dei limiti all'ammontare di
+memoria di un processo che può essere bloccata e al totale di memoria fisica
+che può dedicare a questo.
+
+
+\section{Il controllo di flusso non locale}
+\label{sec:proc_longjmp}
+
+Il controllo del flusso di un programma in genere viene effettuato con le
+varie istruzioni del linguaggio C, la più bistrattata delle quali è il
+\texttt{goto}, ampiamente deprecato in favore di costrutti più puliti; esiste
+però un caso in l'uso di questa istruzione porta all'implementazione più
+efficiente, 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 la funzione \func{longjump}. 
 
 
 \section{La gestione di parametri e opzioni}
-\label{sec:parameter_options}
+\label{sec:proc_options}
 
 Il passaggio dei parametri e delle variabili di ambiente dalla riga di comando
 al singolo programma quando viene lanciato è effettuato attraverso le
@@ -430,7 +710,7 @@ ciascuna delle quali viene considerata un parametro; di default per
 individuare le parole viene usato come separatore lo spazio (comportamento
 modificabile attraverso il settaggio della variabile di ambiente IFS).
 
-Nella scansione viene costruito l'array di puntatori \texttt{argv} inserendo
+Nella scansione viene costruito il vettore di puntatori \texttt{argv} inserendo
 in successione il puntatore alla stringa costituente l'$n$-simo parametro; la
 variabile \texttt{argc} viene inizializzata al numero di parametri trovati, in
 questo modo il primo parametro è sempre il nome del programma (vedi \nfig).
@@ -442,7 +722,7 @@ In generale un programma unix riceve da linea di comando sia i parametri che
 le opzioni, queste ultime sono standardizzate per essere riconosciute come
 tali: un elemento di \texttt{argv} che inizia con \texttt{-} e che non sia un
 singolo \texttt{-} o \texttt{--} viene considerato un'opzione.  In in genere
-le opzioni sono costituite da un lettera preceduta dal meno e possono avere o
+le opzioni sono costituite da una lettera preceduta dal meno e possono avere o
 no un parametro associato; un comando tipico può essere cioè qualcosa del
 tipo:
 \begin{verbatim}
@@ -479,7 +759,7 @@ considerata conclusa.
 
 Quando la funzione trova un'opzione essa ritorna il valore numerico del
 carattere, in questo modo si possono prendere le azioni relative usando un
-case; la funzione inizializza inoltre alcune varibili globali:
+case; la funzione inizializza inoltre alcune variabili globali:
 \begin{itemize}
 \item \texttt{char * optarg} contiene il puntatore alla stringa argomento
   dell'opzione.
@@ -490,8 +770,7 @@ case; la funzione inizializza inoltre alcune varibili globali:
 \item \texttt{int optopt} contiene il carattere dell'opzione non riconosciuta.
 \end{itemize}
 
-In \nfig è mostrato un programma di esempio, 
-
+In \nfig\ è mostrato un programma di esempio, 
 
 \begin{figure}[htbp]
   \footnotesize
@@ -548,5 +827,55 @@ versione estesa di \texttt{getopt}.
 
 
 \subsection{Le variabili di ambiente}
-\label{sec:proc_env_var}
+\label{sec:proc_environ}
+
+Oltre ai parametri passati da linea di comando ogni processo riceve dal
+sistema un \textsl{ambiente}, nella forma di una lista di variabili
+(\textit{environment list}) messa a disposizione dal processo costruita nella
+chiamata ad \func{exec} che lo ha lanciato.
+
+Come per la lista dei parametri anche questa lista è un array di puntatori a
+caratteri, ciascuno dei quali punta ad una stringa (terminata da un null). A
+differenza di \var{argv[]} però in questo caso non si ha la lunghezza
+dell'array dato da un equivalente di \var{argc}, ma la lista è terminata da un
+puntatore nullo.
+
+L'indirizzo della lista delle variabili di ambiente è passato attraverso la
+variabile globale \var{environ}, a cui si può accedere attraverso una semplice
+dichiarazione del tipo:
+\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
+extern char ** environ;
+\end{lstlisting}
+un esempio del contenuto dell'ambiente, in si è riportato un estratto delle
+variabili che normalmente sono definite dal sistema, è riportato in \nfig.
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=11cm]{img/environ_var.eps}
+  \caption{Esempio di lista delle variabili di ambiente.}
+  \label{fig:proc_envirno_list}
+\end{figure}
+
+Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo
+\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate
+in \curfig, sono definite dal sistema per queste c'è la convezione di usare
+nomi espressi in caratteri maiuscoli.
+
+Il kernel non usa mai queste variabili, il loro uso e la loro intepretazione è
+riservata alle applicazioni e ad alcune funzioni di libreria; in genere esse
+costituiscono un modo comodo per definire un comportamento specifico senza
+dover ricorrere all'uso di opzioni a linea di comando o di file di
+configurazione. 
+
+La shell ad esempio ne usa molte per il suo funzionamento (come \var{PATH} per
+la ricerca dei comadi), e alcune di esse (come \var{HOME}, \var{USER}, etc.)
+sono definite al login. In genere è cura dell'amministratore definire le
+opportune variabili di ambiente in uno script di avvio. Alcune servono poi
+come riferimento generico per molti programmi (come \var{EDITOR} che indica
+l'editor preferito da invocare in caso di ncessità).
+
+Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più
+comuni), come riportato in \ntab. GNU/Linux le supporta tutte e ne definisce
+anche altre per una lista parziale si può controllare \cmd{man environ}
+
+