Rinominati app_a e app_b
[gapil.git] / process.tex
index 52da830dcb9928b492b66bb79d68fff7a4baca9c..e663713f93584f9029a0cc657cbee66cd7bed344 100644 (file)
@@ -53,15 +53,15 @@ linker darebbe luogo ad errori.
 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
@@ -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}).
 
@@ -347,9 +347,9 @@ programma C viene suddiviso nei seguenti segmenti:
   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{verbatim}
+\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.
@@ -357,9 +357,9 @@ programma C viene suddiviso nei seguenti segmenti:
   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 variabili vengono inizializzate a
   zero (ed i puntatori a \texttt{NULL}). 
@@ -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}
@@ -435,34 +435,32 @@ maniera indiretta attraverso dei puntatori.
 
 Le funzioni previste dallo standard ANSI C per la gestione della memoria sono
 quattro, i prototipi sono i seguenti:
-\begin{prototype}{stdlib.h}{void *calloc(size\_t size)}
+\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}.
-\end{prototype}
-\begin{prototype}{stdlib.h}{void *malloc(size\_t size)}
+\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}.
-\end{prototype}
-\begin{prototype}{stdlib.h}{void free(void *ptr)}
-  Disalloca lo spazio di memoria puntato da \texttt{ptr}.
-
-  La funzione non ritorna nulla.
-\end{prototype}
-\begin{prototype}{stdlib.h}{void *realloc(void *ptr, size\_t size)}
+\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}.
-\end{prototype}
+\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
@@ -498,13 +496,12 @@ 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 \texttt{realloc} possa
-camabiare comporta che si deve sempre riassegnare al puntatore passato per il
+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 è
@@ -521,7 +518,6 @@ 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
@@ -536,11 +532,12 @@ 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:proc_mem_advanced}) che permettono di tracciare le allocazioni e
+\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}
 
@@ -559,29 +556,141 @@ segmento di stack della funzione corrente. La sintassi 
 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, in particolare il fatto che
-la memoria venga rilasciata automaticamente 
-in particolare in Linux
-la funzione è molto veloce e non viene sprecato spazio, non dovendo gestire un
-pool di zone di memoria da riservare; si evita così anche la frammentazione. 
-
-Gli svantaggi sono che quando 
-
+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{La personalizzazione delle funzioni di allocazione} 
-\label{sec:proc_mem_malloc_custom}
+\subsection{La personalizzazione delle funzioni di allocazione} 
+\label{sec:proc_mem_malloc_custom}
 
 
 \subsection{Il controllo della memoria virtuale}  
-\label{sec:proc_mem_mlock}
+\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_flux}
+\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}
@@ -718,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}
+
+