X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=b25c6582a1db27571ba476e832190f6f73807e1c;hp=be725cdfa077dceb0143a4e0b48c180415233a1d;hb=04a547df13e4c672d95e1060e1ada9ae2e1fcb2f;hpb=4d46f47e3a0e08440812b334f79489d92814e6d2 diff --git a/process.tex b/process.tex index be725cd..b25c658 100644 --- a/process.tex +++ b/process.tex @@ -248,8 +248,7 @@ di quelli installati con il sistema,\footnote{in un sistema GNU/Linux che segue le specifiche del \textit{Filesystem Hierarchy Standard} (per maggiori informazioni si consulti sez.~1.2.3 di \cite{AGL}) si trovano sotto \texttt{/usr/include}.} o fra virgolette, nel qual caso si fa riferimento -ad una versione locale, da indicare con un \itindsub{pathname}{relativo} -\textit{pathname} relativo: +ad una versione locale, da indicare con un \textit{pathname} relativo: \includecodesnip{listati/main_include.c} Si tenga presente che oltre ai nomi riservati a livello generale di cui si è @@ -427,10 +426,10 @@ usare un multiplo di 256, di avere uno stato di uscita uguale a zero, che verrebbe interpretato come un successo. Per questo motivo in \headfile{stdlib.h} sono definite, seguendo lo standard -POSIX, le due costanti \const{EXIT\_SUCCESS} e \const{EXIT\_FAILURE}, da usare -sempre per specificare lo stato di uscita di un processo. Su Linux, ed in -generale in qualunque sistema POSIX, ad esse sono assegnati rispettivamente i -valori 0 e 1. +POSIX, le due costanti \constd{EXIT\_SUCCESS} e \constd{EXIT\_FAILURE}, da +usare sempre per specificare lo stato di uscita di un processo. Su Linux, ed +in generale in qualunque sistema POSIX, ad esse sono assegnati rispettivamente +i valori 0 e 1. \itindend{exit~status} @@ -482,7 +481,7 @@ chiamata ad una funzione che effettui tali operazioni all'uscita dal programma. A questo scopo lo standard ANSI C prevede la possibilità di registrare un certo numero di funzioni che verranno eseguite all'uscita dal programma,\footnote{nel caso di \func{atexit} lo standard POSIX.1-2001 - richiede che siano registrabili almeno \const{ATEXIT\_MAX} funzioni (il + richiede che siano registrabili almeno \constd{ATEXIT\_MAX} funzioni (il valore può essere ottenuto con \func{sysconf}, vedi sez.~\ref{sec:sys_limits}).} sia per la chiamata ad \func{exit} che per il ritorno di \code{main}. La prima funzione che si può utilizzare a tal fine è @@ -663,7 +662,7 @@ bit e di 8kb sulle alpha. Con le versioni più recenti del kernel è possibile anche utilizzare pagine di dimensioni maggiori (di 4Mb, dette \textit{huge page}), per sistemi con grandi quantitativi di memoria in cui l'uso di pagine troppo piccole comporta una perdita di prestazioni. In alcuni sistemi -la costante \const{PAGE\_SIZE}, definita in \headfile{limits.h}, indica la +la costante \constd{PAGE\_SIZE}, definita in \headfile{limits.h}, indica la dimensione di una pagina in byte, con Linux questo non avviene e per ottenere questa dimensione si deve ricorrere alla funzione \func{getpagesize} (vedi sez.~\ref{sec:sys_memory_res}). @@ -754,10 +753,10 @@ processo. Essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di indirizzi virtuali ai quali il processo può accedere. Solitamente un programma C viene suddiviso nei seguenti segmenti: \index{segmento!testo|(} -\index{segmento!dati(} +\index{segmento!dati|(} \itindbeg{heap} \itindbeg{stack} -\begin{enumerate*} +\begin{enumerate} \item Il \textsl{segmento di testo} o \textit{text segment}. Contiene il codice del programma, delle funzioni di librerie da esso utilizzate, e le costanti. Normalmente viene condiviso fra tutti i processi che eseguono lo @@ -783,7 +782,7 @@ programma C viene suddiviso nei seguenti segmenti: globale è che essa può essere vista solo all'interno della funzione in cui è dichiarata.} e la memoria allocata dinamicamente. Di norma è diviso in tre parti: - \begin{itemize*} + \begin{itemize} \item Il segmento dei dati inizializzati, che contiene le variabili il cui valore è stato assegnato esplicitamente. Ad esempio se si definisce: \includecodesnip{listati/pi.c} @@ -810,7 +809,7 @@ programma C viene suddiviso nei seguenti segmenti: disallocare la memoria dinamica con le apposite funzioni (vedi sez.~\ref{sec:proc_mem_alloc}), ma il suo limite inferiore, quello adiacente al segmento dei dati non inizializzati, ha una posizione fissa. - \end{itemize*} + \end{itemize} \item Il segmento di \textit{stack}, che contiene quello che viene chiamato lo ``\textit{stack}'' del programma. Tutte le volte che si effettua una chiamata ad una funzione è qui che viene salvato l'indirizzo di ritorno e le @@ -834,7 +833,7 @@ programma C viene suddiviso nei seguenti segmenti: La dimensione di questo segmento aumenta seguendo la crescita dello \textit{stack} del programma, ma non viene ridotta quando quest'ultimo si restringe. -\end{enumerate*} +\end{enumerate} \begin{figure}[htb] \centering @@ -878,7 +877,7 @@ mai salvato sul file che contiene l'eseguibile, dato che viene sempre inizializzato a zero al caricamento del programma. \index{segmento!testo|)} -\index{segmento!dati)} +\index{segmento!dati|)} \itindend{heap} \itindend{stack} @@ -1074,25 +1073,23 @@ Il problema è che l'esaurimento della memoria può avvenire in qualunque momento, in corrispondenza ad una qualunque chiamata di \func{malloc} che può essere in una sezione del codice che non ha alcuna relazione con la funzione che contiene l'errore. Per questo motivo è sempre molto difficile trovare un -\textit{memory leak}. - -In C e C++ il problema è particolarmente sentito. In C++, per mezzo della -programmazione ad oggetti, il problema dei \textit{memory leak} si può -notevolmente ridimensionare attraverso l'uso accurato di appositi oggetti come -gli \textit{smartpointers}. Questo però in genere va a scapito delle -prestazioni dell'applicazione in esecuzione. - -% TODO decidere cosa fare di questo che segue -% 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é -% 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. +\textit{memory leak}. In C e C++ il problema è particolarmente sentito. In +C++, per mezzo della programmazione ad oggetti, il problema dei \textit{memory + leak} si può notevolmente ridimensionare attraverso l'uso accurato di +appositi oggetti come gli \textit{smartpointers}. Questo però in genere va a +scapito delle prestazioni dell'applicazione in esecuzione. + +% TODO decidere cosa fare di questo che segue 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é l'infrastruttura del +% linguaggio gestisce automaticamente la cosiddetta +% \itindex{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 @@ -1155,7 +1152,7 @@ Gli svantaggi sono che questa funzione non è disponibile su tutti gli Unix, e non è inserita né nello standard POSIX né in SUSv3 (ma è presente in BSD), il suo utilizzo quindi limita la portabilità dei programmi. Inoltre la funzione non può essere usata nella lista degli argomenti di una funzione, perché lo -spazio verrebbe allocato nel mezzo degli stessi. Inoltre non è chiaramente +spazio verrebbe allocato nel mezzo degli stessi. Inoltre non è chiaramente possibile usare \func{alloca} per allocare memoria che deve poi essere usata anche al di fuori della funzione in cui essa viene chiamata, dato che all'uscita dalla funzione lo spazio allocato diventerebbe libero, e potrebbe @@ -1174,7 +1171,6 @@ comportamento del programma può risultare indefinito, dando luogo ad una \textit{segment violation} la prima volta che cercherà di accedere alla memoria non effettivamente disponibile. - \index{segmento!dati|(} \itindbeg{heap} @@ -1200,9 +1196,9 @@ uguale di 500). La prima funzione è \funcd{brk}, ed il suo prototipo è: La funzione è un'interfaccia all'omonima \textit{system call} ed imposta l'indirizzo finale del segmento dati di un processo (più precisamente dello \textit{heap}) all'indirizzo specificato da \param{addr}. Quest'ultimo deve -essere un valore ragionevole, e la dimensione totale non deve comunque -eccedere un eventuale limite (vedi sez.~\ref{sec:sys_resource_limit}) imposto -sulle dimensioni massime del segmento dati del processo. +essere un valore ragionevole e la dimensione totale non deve comunque eccedere +un eventuale limite (vedi sez.~\ref{sec:sys_resource_limit}) sulle dimensioni +massime del segmento dati del processo. Il valore di ritorno della funzione fa riferimento alla versione fornita dalla \acr{glibc}, in realtà in Linux la \textit{system call} corrispondente @@ -1370,7 +1366,7 @@ sez.~\ref{sec:proc_exec}). Il sistema pone dei limiti all'ammontare di memoria di un processo che può essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo standard POSIX.1 richiede che sia definita in \headfile{unistd.h} la macro -\macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il +\macrod{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il \textit{memory locking}. Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce @@ -1454,10 +1450,10 @@ espressi dalle costanti riportate in tab.~\ref{tab:mlockall_flags}. \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \const{MCL\_CURRENT}& blocca tutte le pagine correntemente mappate nello - spazio di indirizzi del processo.\\ - \const{MCL\_FUTURE} & blocca tutte le pagine che verranno mappate nello - spazio di indirizzi del processo.\\ + \constd{MCL\_CURRENT}& blocca tutte le pagine correntemente mappate nello + spazio di indirizzi del processo.\\ + \constd{MCL\_FUTURE} & blocca tutte le pagine che verranno mappate nello + spazio di indirizzi del processo.\\ \hline \end{tabular} \caption{Valori e significato dell'argomento \param{flags} della funzione @@ -1636,20 +1632,20 @@ tipologia di errore riscontrata. \textbf{Valore} & \textbf{Significato} \\ \hline \hline - \const{MCHECK\_OK} & Riportato a \func{mprobe} se nessuna - inconsistenza è presente.\\ - \const{MCHECK\_DISABLED}& Riportato a \func{mprobe} se si è chiamata - \func{mcheck} dopo aver già usato - \func{malloc}.\\ - \const{MCHECK\_HEAD} & I dati immediatamente precedenti il buffer sono - stati modificati, avviene in genere quando si - decrementa eccessivamente il valore di un - puntatore scrivendo poi prima dell'inizio del - buffer.\\ - \const{MCHECK\_TAIL} & I dati immediatamente seguenti il buffer sono - stati modificati, succede quando si va scrivere - oltre la dimensione corretta del buffer.\\ - \const{MCHECK\_FREE} & Il buffer è già stato disallocato.\\ + \constd{MCHECK\_OK} & Riportato a \func{mprobe} se nessuna + inconsistenza è presente.\\ + \constd{MCHECK\_DISABLED}& Riportato a \func{mprobe} se si è chiamata + \func{mcheck} dopo aver già usato + \func{malloc}.\\ + \constd{MCHECK\_HEAD} & I dati immediatamente precedenti il buffer sono + stati modificati, avviene in genere quando si + decrementa eccessivamente il valore di un + puntatore scrivendo poi prima dell'inizio del + buffer.\\ + \constd{MCHECK\_TAIL} & I dati immediatamente seguenti il buffer sono + stati modificati, succede quando si va scrivere + oltre la dimensione corretta del buffer.\\ + \constd{MCHECK\_FREE} & Il buffer è già stato disallocato.\\ \hline \end{tabular} \caption{Valori dello stato dell'allocazione di memoria ottenibili dalla @@ -1860,7 +1856,7 @@ Normalmente \func{getopt} compie una permutazione degli elementi di opzioni sono spostati in coda al vettore. Oltre a questa esistono altre due modalità di gestire gli elementi di \param{argv}; se \param{optstring} inizia con il carattere ``\texttt{+}'' (o è impostata la variabile di ambiente -\macro{POSIXLY\_CORRECT}) la scansione viene fermata non appena si incontra un +\cmd{POSIXLY\_CORRECT}) la scansione viene fermata non appena si incontra un elemento che non è un'opzione. L'ultima modalità, usata quando un programma può gestire la mescolanza fra @@ -2319,7 +2315,7 @@ relativo puntatore fra le funzioni. \subsection{Il passaggio di un numero variabile di argomenti} \label{sec:proc_variadic} -\index{funzioni!variadic|(} +\index{funzioni!\textit{variadic}|(} Come vedremo nei capitoli successivi, non sempre è possibile specificare un numero fisso di argomenti per una funzione. Lo standard ISO C prevede nella @@ -2377,6 +2373,8 @@ quelli variabili vengono indicati in maniera generica dalla pertanto quella sequenziale, in cui vengono estratti dallo \textit{stack} secondo l'ordine in cui sono stati scritti nel prototipo della funzione. +\macrobeg{va\_start} + Per fare questo in \headfile{stdarg.h} sono definite delle macro specifiche, previste dallo standard ISO C89, che consentono di eseguire questa operazione. La prima di queste macro è \macro{va\_start}, che inizializza opportunamente @@ -2396,6 +2394,8 @@ deve essere una apposita variabile di tipo \type{va\_list}; il parametro \param{last} deve indicare il nome dell'ultimo degli argomenti fissi dichiarati nel prototipo della funzione \textit{variadic}. +\macrobeg{va\_arg} + La seconda macro di gestione delle liste di argomenti di una funzione \textit{variadic} è \macro{va\_arg}, che restituisce in successione un argomento della lista; la sua definizione è: @@ -2423,8 +2423,10 @@ effettivamente forniti si otterranno dei valori indefiniti. Si avranno risultati indefiniti anche quando si chiama \macro{va\_arg} specificando un tipo che non corrisponde a quello usato per il corrispondente argomento. +\macrobeg{va\_end} + Infine una volta completata l'estrazione occorre indicare che si sono concluse -le operazioni con la macro \macro{va\_end}, la cui definizione è: +le operazioni con la macro \macrod{va\_end}, la cui definizione è: {\centering \begin{funcbox}{ @@ -2467,6 +2469,10 @@ caso però al ritorno della funzione \macro{va\_arg} non può più essere usata (anche se non si era completata l'estrazione) dato che il valore di \param{ap} risulterebbe indefinito. +\macroend{va\_start} +\macroend{va\_arg} +\macroend{va\_end} + Esistono dei casi in cui è necessario eseguire più volte la scansione degli argomenti e poter memorizzare una posizione durante la stessa. In questo caso sembrerebbe naturale copiarsi la lista degli argomenti \param{ap} con una @@ -2489,7 +2495,7 @@ utilizzare solo attraverso dalle opportune funzioni di gestione. Per questo motivo una variabile di tipo \type{va\_list} non può essere assegnata direttamente ad un'altra variabile dello stesso tipo, ma 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 + posto \macrod{\_\_va\_copy} che era il nome proposto in una bozza dello standard.} ha previsto una macro ulteriore che permette di eseguire la copia di una lista degli argomenti: @@ -2503,7 +2509,7 @@ copia di una lista degli argomenti: La macro copia l'attuale della lista degli argomenti \param{src} su una nuova lista \param{dest}. Anche in questo caso è buona norma chiudere ogni -esecuzione di una \macro{va\_copy} con una corrispondente \macro{va\_end} sul +esecuzione di una \macrod{va\_copy} con una corrispondente \macro{va\_end} sul nuovo puntatore alla lista degli argomenti. La chiamata di una funzione con un numero variabile di argomenti, posto che la @@ -2535,7 +2541,7 @@ valore speciale per l'ultimo argomento, come fa ad esempio \func{execl} che usa un puntatore \val{NULL} per indicare la fine della lista degli argomenti (vedi sez.~\ref{sec:proc_exec}). -\index{funzioni!variadic|)} +\index{funzioni!\textit{variadic}|)} \subsection{Il controllo di flusso non locale} \label{sec:proc_longjmp} @@ -2625,10 +2631,10 @@ dell'argomento \param{val} deve essere sempre diverso da zero, se si è specificato 0 sarà comunque restituito 1 al suo posto. In sostanza l'esecuzione di \func{longjmp} è analoga a quella di una -istruzione \instruction{return}, solo che invece di ritornare alla riga +istruzione \instr{return}, solo che invece di ritornare alla riga successiva della funzione chiamante, il programma in questo caso ritorna alla posizione della relativa \func{setjmp}. L'altra differenza fondamentale con -\instruction{return} è che il ritorno può essere effettuato anche attraverso +\instr{return} è che il ritorno può essere effettuato anche attraverso diversi livelli di funzioni annidate. L'implementazione di queste funzioni comporta alcune restrizioni dato che esse @@ -2652,13 +2658,13 @@ dei seguenti casi: In generale, dato che l'unica differenza fra la chiamata diretta e quella ottenuta nell'uscita con un \func{longjmp} è costituita dal valore di ritorno di \func{setjmp}, pertanto quest'ultima viene usualmente chiamata all'interno -di un una istruzione \instruction{if} che permetta di distinguere i due casi. +di un una istruzione \instr{if} che permetta di distinguere i due casi. 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 \direct{register}) sono in +delle variabili automatiche (o di quelle dichiarate \dirct{register}) sono in genere indeterminati. Quello che succede infatti è che i valori delle variabili che sono tenute in