X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=43dac1d9e82f79237febc7703000a9bf8d51fc18;hp=1127247800e688da58249ada4414f047c635718c;hb=9a6d19e384fe9b1afbe4d9124ac34eaf7aa57562;hpb=43863d64be274fa4adfa5db745120aedb5f421c9 diff --git a/process.tex b/process.tex index 1127247..43dac1d 100644 --- a/process.tex +++ b/process.tex @@ -43,29 +43,30 @@ tutti gli altri.\footnote{questo non Quando un programma viene lanciato il kernel esegue un'opportuna routine di avvio, usando il programma \cmd{ld-linux.so}. Questo programma prima carica -le librerie condivise che servono al programma, poi effettua il link dinamico -del codice e 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 \textit{linkati} alle librerie condivise -quando vengono avviati. La procedura è controllata da alcune variabili di -ambiente e dal contenuto di \file{/etc/ld.so.conf}. I dettagli sono riportati -nella man page di \cmd{ld.so}. +le librerie condivise che servono al programma, poi effettua il collegamento +dinamico del codice e 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 \textsl{collegati} +alle librerie condivise quando vengono avviati. La procedura è controllata da +alcune variabili di ambiente e dal contenuto di \file{/etc/ld.so.conf}. I +dettagli sono riportati nella man page di \cmd{ld.so}. Il sistema fa partire qualunque programma chiamando la funzione \func{main}; sta al programmatore chiamare così la funzione principale del programma da cui si suppone iniziare l'esecuzione; in ogni caso senza questa funzione lo stesso -\textit{linker} darebbe luogo ad errori. - -Lo standard ISO C specifica che la funzione \func{main} può 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: +\textit{linker} (si chiama così il programma che effettua i collegamenti di +cui sopra) darebbe luogo ad errori. Lo standard ISO C specifica che la +funzione \func{main} può 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: \includecodesnip{listati/main_def.c} -In realtà nei sistemi Unix esiste un'altro modo per definire la funzione +In realtà nei sistemi Unix esiste un altro modo per definire la funzione \func{main}, che prevede la presenza di un terzo argomento, \code{char - *envp[]}, che fornisce l'\textsl{ambiente} (vedi sez.~\ref{sec: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 (vedi sez.~\ref{sec:proc_environ}) +l'\textsl{ambiente} 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} @@ -151,7 +152,7 @@ non vengono salvati e le eventuali funzioni registrate con \func{atexit} e La funzione chiude tutti i file descriptor appartenenti al processo (si tenga presente che questo non comporta il salvataggio dei dati bufferizzati degli -stream), fa sì che ogni figlio del processo sia ereditato da \cmd{init} (vedi +stream), fa sì che ogni figlio del processo sia adottato da \cmd{init} (vedi cap.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di uscita specificato in \param{status} che può essere raccolto usando la @@ -265,7 +266,7 @@ 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.} + è stato esteso anche per macchine a 32 bit.} Come accennato in cap.~\ref{cha:intro_unix} questo spazio di indirizzi è virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del @@ -374,8 +375,8 @@ seguenti segmenti: puntatori a \val{NULL}).\footnote{si ricordi che questo vale solo per le variabili che vanno nel segmento dati, e non è affatto vero in generale.} - Storicamente questo segmento viene chiamato BSS (da \textit{block started by - symbol}). La sua dimensione è fissa. + Storicamente questa seconda parte del segmento dati viene chiamata BSS (da + \textit{Block Started by Symbol}). La sua dimensione è fissa. \item Lo \textit{heap}. Tecnicamente lo si può considerare l'estensione del segmento dati, a cui di solito è posto giusto di seguito. È qui che avviene @@ -401,7 +402,7 @@ seguenti segmenti: \begin{figure}[htb] \centering - \includegraphics[height=12cm]{img/memory_layout} + \includegraphics[height=11cm]{img/memory_layout} \caption{Disposizione tipica dei segmenti di memoria di un processo.} \label{fig:proc_mem_layout} \end{figure} @@ -434,10 +435,10 @@ una funzione e per le sue variabili locali (le cosiddette \textsl{variabili per queste variabili viene allocato nello stack quando viene eseguita la funzione e liberato quando si esce dalla medesima. -Esiste però un terzo tipo di allocazione, l'\textsl{allocazione dinamica della - memoria}, che non è prevista direttamente all'interno del linguaggio C, ma -che è necessaria quando il quantitativo di memoria che serve è determinabile -solo durante il corso dell'esecuzione del programma. +Esiste però un terzo tipo di allocazione, l'\textsl{allocazione dinamica} +della memoria, che non è prevista direttamente all'interno del linguaggio C, +ma che è necessaria quando il quantitativo di memoria che serve è +determinabile solo durante il corso dell'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 @@ -544,9 +545,9 @@ uso una versione meno efficiente delle funzioni suddette, che per tollerante nei confronti di piccoli errori come quello di chiamate doppie a \func{free}. In particolare: \begin{itemize} -\item se la variabile è posta a zero gli errori vengono ignorati. +\item se la variabile è posta a zero gli errori vengono ignorati; \item se è posta ad 1 viene stampato un avviso sullo \textit{standard error} - (vedi sez.~\ref{sec:file_std_stream}). + (vedi sez.~\ref{sec:file_std_stream}); \item se è posta a 2 viene chiamata \func{abort}, che in genere causa l'immediata conclusione del programma. \end{itemize} @@ -578,12 +579,13 @@ dell'applicazione in esecuzione. In altri linguaggi come il java e recentemente il C\# il problema non si pone nemmeno perché la gestione della memoria viene fatta totalmente in maniera automatica, ovvero il programmatore non deve minimamente preoccuparsi di -liberare la memoria allocata precedentemente quando non serve più, poiché il -framework gestisce automaticamente la cosiddetta \textit{garbage collection}. -In tal caso, attraverso meccanismi simili a quelli del \textit{reference - counting}, quando una zona di memoria precedentemente allocata non è più -riferita da nessuna parte del codice in esecuzione, può essere deallocata -automaticamente in qualunque momento dall'infrastruttura. +liberare la memoria allocata precedentemente quando non serve più, poiché +l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta +\index{\textit{garbage~collection}}\textit{garbage collection}. In tal caso, +attraverso meccanismi simili a quelli del \textit{reference counting}, quando +una zona di memoria precedentemente allocata non è più riferita da nessuna +parte del codice in esecuzione, può essere deallocata automaticamente in +qualunque momento dall'infrastruttura. Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione (inoltre le applicazioni sviluppate con tali linguaggi di solito non sono @@ -597,20 +599,19 @@ allocata da un oggetto. Per limitare l'impatto di questi problemi, e semplificare la ricerca di eventuali errori, l'implementazione delle routine di allocazione delle \acr{glibc} mette a disposizione una serie di funzionalità che permettono di -tracciare le allocazioni e le disallocazione, e definisce anche una serie di +tracciare le allocazioni e le disallocazioni, e definisce anche una serie di possibili \textit{hook} (\textsl{ganci}) che permettono di sostituire alle funzioni di libreria una propria versione (che può essere più o meno specializzata per il debugging). Esistono varie librerie che forniscono dei sostituti opportuni delle routine di allocazione in grado, senza neanche ricompilare il programma,\footnote{esempi sono \textit{Dmalloc} - \href{http://dmalloc.com/}{http://dmalloc.com/} di Gray Watson ed + \href{http://dmalloc.com/}{\textsf{http://dmalloc.com/}} di Gray Watson ed \textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche molto complesse riguardo l'allocazione della memoria. - -\subsection{La funzione \func{alloca}} -\label{sec:proc_mem_alloca} +\subsection{Le funzioni \func{alloca}, \func{brk} e \func{sbrk}} +\label{sec:proc_mem_sbrk_alloca} Una possibile alternativa all'uso di \func{malloc}, che non soffre dei problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in @@ -666,14 +667,12 @@ Questo cui torneremo in sez.~\ref{sec:proc_auto_var}. -\subsection{Le funzioni \func{brk} e \func{sbrk}} -\label{sec:proc_mem_sbrk} - -Queste due funzioni vengono utilizzate soltanto quando è necessario effettuare -direttamente la gestione della memoria associata allo spazio dati di un -processo, ad esempio qualora si debba implementare la propria versione delle -routine di allocazione della memoria viste in sez.~\ref{sec:proc_mem_malloc}. -La prima funzione è \funcd{brk}, ed il suo prototipo è: +Le due funzioni seguenti vengono utilizzate soltanto quando è necessario +effettuare direttamente la gestione della memoria associata allo spazio dati +di un processo, ad esempio qualora si debba implementare la propria versione +delle routine di allocazione della memoria viste in +sez.~\ref{sec:proc_mem_malloc}. La prima funzione è \funcd{brk}, ed il suo +prototipo è: \begin{prototype}{unistd.h}{int brk(void *end\_data\_segment)} Sposta la fine del segmento dei dati. @@ -768,7 +767,7 @@ bloccata oppure no. Il \textit{memory lock} persiste fintanto che il processo che 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 suoi \textit{memory lock}. Infine \textit{memory lock} non sono +tutti i suoi \textit{memory lock}. Infine i \textit{memory lock} non sono ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio sono mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che @@ -892,17 +891,17 @@ manipolare ed utilizzare le variabili di ambiente. \subsection{Il formato degli argomenti} \label{sec:proc_par_format} -In genere passaggio degli argomenti al programma viene effettuato dalla shell, -che si incarica di leggere la linea di comando e di effettuarne la scansione -(il cosiddetto \textit{parsing}) per individuare le parole che la compongono, -ciascuna delle quali viene considerata un argomento. Di norma per individuare -le parole viene usato come carattere di separazione lo spazio o il tabulatore, -ma il comportamento è modificabile attraverso l'impostazione della variabile -di ambiente \cmd{IFS}. +In genere il passaggio degli argomenti al programma viene effettuato dalla +shell, che si incarica di leggere la linea di comando e di effettuarne la +scansione (il cosiddetto \textit{parsing}) per individuare le parole che la +compongono, ciascuna delle quali viene considerata un argomento. Di norma per +individuare le parole viene usato come carattere di separazione lo spazio o il +tabulatore, ma il comportamento è modificabile attraverso l'impostazione della +variabile di ambiente \cmd{IFS}. \begin{figure}[htb] \centering - \includegraphics[width=11cm]{img/argv_argc} + \includegraphics[width=13cm]{img/argv_argc} \caption{Esempio dei valori di \param{argv} e \param{argc} generati nella scansione di una riga di comando.} \label{fig:proc_argv_argc} @@ -921,7 +920,7 @@ questo meccanismo In generale un programma Unix riceve da linea di comando sia gli argomenti che le opzioni, queste ultime sono standardizzate per essere riconosciute come tali: un elemento di \param{argv} che inizia con il carattere \texttt{'-'} e -che non sia un singolo \texttt{'-'} o un \texttt{'--'} viene considerato +che non sia un singolo \texttt{'-'} o un \texttt{'-{}-'} viene considerato un'opzione. In genere le opzioni sono costituite da una lettera singola (preceduta dal carattere \cmd{'-'}) e possono avere o no un parametro associato; un comando tipico può essere quello mostrato in @@ -958,9 +957,9 @@ La modalit funzione all'interno di un ciclo, fintanto che essa non ritorna il valore -1 che indica che non ci sono più opzioni. Nel caso si incontri un'opzione non dichiarata in \param{optstring} viene ritornato il carattere \texttt{'?'} -mentre se un opzione che lo richiede non è seguita da un parametro viene +mentre se un'opzione che lo richiede non è seguita da un parametro viene ritornato il carattere \texttt{':'}, infine se viene incontrato il valore -\texttt{'--'} la scansione viene considerata conclusa, anche se vi sono altri +\texttt{'-{}-'} la scansione viene considerata conclusa, anche se vi sono altri elementi di \param{argv} che cominciano con il carattere \texttt{'-'}. \begin{figure}[htb] @@ -1019,7 +1018,7 @@ effettua il riordinamento del vettore \param{argv}. \subsection{Opzioni in formato esteso} \label{sec:proc_opt_extended} -Un'estensione di questo schema è costituito dalle cosiddette +Un'estensione di questo schema è costituita dalle cosiddette \textit{long-options} espresse nella forma \cmd{-{}-option=parameter}, anche la gestione di queste ultime è stata standardizzata attraverso l'uso di una versione estesa di \func{getopt}. @@ -1050,7 +1049,7 @@ pi fig.~\ref{fig:proc_envirno_list}. \begin{figure}[htb] \centering - \includegraphics[width=11cm]{img/environ_var} + \includegraphics[width=13cm]{img/environ_var} \caption{Esempio di lista delle variabili di ambiente.} \label{fig:proc_envirno_list} \end{figure} @@ -1074,7 +1073,7 @@ delle relative chiamate (si veda sez.~\ref{sec:proc_exec}). La shell ad esempio ne usa molte per il suo funzionamento (come \texttt{PATH} per la ricerca dei comandi, o \texttt{IFS} per la scansione degli argomenti), -e alcune di esse (come \texttt{HOME}, \texttt{USER}, etc.) sono definite al +e alcune di esse (come \texttt{HOME}, \texttt{USER}, ecc.) sono definite al login (per i dettagli si veda sez.~\ref{sec:sess_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 @@ -1084,7 +1083,7 @@ necessit Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più comuni), come riportato in tab.~\ref{tab:proc_env_var}. GNU/Linux le supporta tutte e ne definisce anche altre: per una lista più completa si può -controllare \cmd{man environ}. +controllare \cmd{man 5 environ}. \begin{table}[htb] \centering @@ -1199,7 +1198,7 @@ separatamente nome e valore della variabile di ambiente, inoltre il valore di variabile esista già, sovrascrivendola se diverso da zero, lasciandola immutata se uguale a zero. -La seconda funzione prende come argomento una stringa analoga quella +La seconda funzione prende come argomento una stringa analoga a quella restituita da \func{getenv}, e sempre nella forma \code{NOME=valore}. Se la variabile specificata non esiste la stringa sarà aggiunta all'ambiente, se invece esiste il suo valore sarà impostato a quello specificato da @@ -1308,21 +1307,23 @@ Come vedremo nei capitoli successivi, non sempre numero fisso di argomenti per una funzione. Lo standard ISO C prevede nella sua sintassi la possibilità di definire delle \textit{variadic function}\index{variadic} che abbiano un numero variabile di argomenti, -attraverso l'uso della \textit{ellipsis} \code{...} nella dichiarazione della -funzione; ma non provvede a livello di linguaggio alcun meccanismo con cui -dette funzioni possono accedere ai loro argomenti. - -L'accesso viene invece realizzato dalle librerie standard che provvedono gli -strumenti adeguati. L'uso delle \textit{variadic function} prevede tre punti: -\begin{itemize*} +attraverso l'uso nella dichiarazione della funzione dello speciale costrutto +``\texttt{\textellipsis}'', che viene chiamato \textit{ellipsis}. + +Lo standard però non provvede a livello di linguaggio alcun meccanismo con cui +dette funzioni possono accedere ai loro argomenti. L'accesso viene pertanto +realizzato a livello delle librerie standard del C che provvedono gli +strumenti adeguati. L'uso di una \textit{variadic function} prevede quindi +tre punti: +\begin{itemize} \item \textsl{Dichiarare} la funzione come \textit{variadic} usando un prototipo che contenga una \textit{ellipsis}. -\item \textsl{Definire} la funzione come \textit{variadic} usando lo stesso +\item \textsl{Definire} la funzione come \textit{variadic} usando la stessa \textit{ellipsis}, ed utilizzare le apposite macro che consentono la gestione di un numero variabile di argomenti. -\item \textsl{Chiamare} la funzione specificando prima gli argomenti fissi, e - a seguire gli addizionali. -\end{itemize*} +\item \textsl{Invocare} la funzione specificando prima gli argomenti fissi, ed + a seguire quelli addizionali. +\end{itemize} Lo standard ISO C prevede che una \textit{variadic function}\index{variadic} abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione @@ -1352,7 +1353,7 @@ L'unica modalit sequenziale; essi verranno estratti dallo stack secondo l'ordine in cui sono stati scritti. Per fare questo in \file{stdarg.h} sono definite delle apposite macro; la procedura da seguire è la seguente: -\begin{enumerate*} +\begin{enumerate} \item Inizializzare un puntatore alla lista degli argomenti di tipo \macro{va\_list} attraverso la macro \macro{va\_start}. \item Accedere ai vari argomenti opzionali con chiamate successive alla macro @@ -1360,8 +1361,8 @@ macro; la procedura da seguire il secondo e così via. \item Dichiarare la conclusione dell'estrazione degli argomenti invocando la macro \macro{va\_end}. -\end{enumerate*} -in generale è perfettamente legittimo richiedere meno argomenti di quelli che +\end{enumerate} +In generale è perfettamente legittimo richiedere meno argomenti di quelli che potrebbero essere stati effettivamente forniti, e nella esecuzione delle \macro{va\_arg} ci si può fermare in qualunque momento ed i restanti argomenti saranno ignorati; se invece si richiedono più argomenti di quelli forniti si @@ -1486,15 +1487,15 @@ programma: quello dell'uscita in caso di errore. \index{salto~non-locale|(} -Il C però non consente di effettuare un salto ad -una etichetta definita in 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 \cite{glibc}, è quello -di un programma nel cui corpo principale vengono letti dei dati in ingresso -sui quali viene eseguita, tramite una serie di funzioni di analisi, una -scansione dei contenuti da si ottengono le indicazioni per l'esecuzione delle -opportune operazioni. +Il C però non consente di effettuare un salto ad una etichetta definita in +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 in \cite{APUE} che in \cite{glibc}, è quello di un programma nel +cui corpo principale vengono letti dei dati in ingresso sui quali viene +eseguita, tramite una serie di funzioni di analisi, una scansione dei +contenuti, da cui si ottengono 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 nei dati in ingresso può accadere @@ -1575,18 +1576,18 @@ pertanto non si pu 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}). + 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. + iterazione; \item come operando per l'operatore di negazione (\code{!}) in una espressione - di controllo di un comando condizionale, di selezione o di iterazione. + 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}. +ottenuta da un \func{longjmp} è costituita dal 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