%% process.tex
%%
-%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to
+%% Copyright (C) 2000-2009 Simone Piccardi. Permission is granted to
%% copy, distribute and/or modify this document under the terms of the GNU Free
%% Documentation License, Version 1.1 or any later version published by the
%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi,
variabili proprie e sarà eseguito in maniera completamente indipendente da
tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma
- \textit{multi-thread}, ma la gestione dei \textit{thread} in Linux sarà
- trattata a parte.}
+ \textit{multi-thread}, ma la gestione dei \itindex{thread} \textit{thread}
+ in Linux sarà trattata a parte in cap.~\ref{cha:threads}.}
\subsection{La funzione \func{main}}
Registra la funzione \param{function} per la chiamata all'uscita dal
programma.
- \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ \bodydesc{La funzione restituisce $0$ in caso di successo e $-1$ in caso di
fallimento, \var{errno} non viene modificata.}
\end{prototype}
\noindent la funzione richiede come argomento l'indirizzo di una opportuna
Registra la funzione \param{function} per la chiamata all'uscita dal
programma.
- \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
fallimento, \var{errno} non viene modificata.}
\end{prototype}
\begin{figure}[htb]
\centering
- \includegraphics[width=9cm]{img/proc_beginend}
+% \includegraphics[width=9cm]{img/proc_beginend}
+ \begin{tikzpicture}[>=stealth]
+ \filldraw[fill=black!35] (-0.3,0) rectangle (12,1);
+ \draw(5.5,0.5) node {\large{kernel}};
+
+ \filldraw[fill=black!15] (1.5,2) rectangle (4,3);
+ \draw (2.75,2.5) node {\texttt{ld-linux.so}};
+ \draw [->] (2.75,1) -- (2.75,2);
+ \draw (2.75,1.5) node [anchor=west]{\texttt{exec}};
+
+ \filldraw[fill=black!15,rounded corners] (1.5,4) rectangle (4,5);
+ \draw (2.75,4.5) node {\texttt{main}};
+
+ \draw [<->, dashed] (2.75,3) -- (2.75,4);
+ \draw [->] (1.5,4.5) -- (0.3,4.5) -- (0.3,1);
+ \draw (0.9,4.5) node [anchor=south] {\texttt{\_exit}};
+
+ \filldraw[fill=black!15,rounded corners] (1.5,6) rectangle (4,7);
+ \draw (2.75,6.5) node {\texttt{funzione}};
+
+ \draw [<->, dashed] (2.75,5) -- (2.75,6);
+ \draw [->] (1.5,6.5) -- (0.05,6.5) -- (0.05,1);
+ \draw (0.9,6.5) node [anchor=south] {\texttt{\_exit}};
+
+ \draw (6.75,4.5) node (exit) [rectangle,fill=black!15,minimum width=2.5cm,minimum height=1cm,rounded corners, draw]{\texttt{exit}};
+
+ \draw[->] (4,6.5) -- node[anchor=south west]{\texttt{exit}} (exit);
+ \draw[->] (4,4.5) -- node[anchor=south]{\texttt{exit}} (exit);
+ \draw[->] (exit) -- node[anchor=east]{\texttt{\_exit}}(6.75,1);
+
+ \draw (10,4.5) node (exithandler1) [rectangle,fill=black!15,rounded corners, draw]{exit handler};
+ \draw (10,5.5) node (exithandler2) [rectangle,fill=black!15,rounded corners, draw]{exit handler};
+ \draw (10,3.5) node (stream) [rectangle,fill=black!15,rounded corners, draw]{chiusura stream};
+
+ \draw[<->, dashed] (exithandler1) -- (exit);
+ \draw[<->, dashed] (exithandler2) -- (exit);
+ \draw[<->, dashed] (stream) -- (exit);
+ \end{tikzpicture}
\caption{Schema dell'avvio e della conclusione di un programma.}
\label{fig:proc_prog_start_stop}
\end{figure}
Benché lo spazio di indirizzi virtuali copra un intervallo molto ampio, solo
una parte di essi è effettivamente allocato ed utilizzabile dal processo; il
tentativo di accedere ad un indirizzo non allocato è un tipico errore che si
-commette quando si è manipolato male un puntatore e genera quello che viene
-chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
-scrivere da un indirizzo per il quale non esiste un'associazione della pagina
-virtuale, il kernel risponde al relativo \itindex{page~fault} \textit{page
- fault} mandando un segnale \const{SIGSEGV} al processo, che normalmente ne
-causa la terminazione immediata.
+commette quando si è manipolato male un puntatore e genera quella che viene
+chiamata una \itindex{segment~violation} \textit{segment violation}. Se si
+tenta cioè di leggere o scrivere da un indirizzo per il quale non esiste
+un'associazione della pagina virtuale, il kernel risponde al relativo
+\itindex{page~fault} \textit{page fault} mandando un segnale \const{SIGSEGV}
+al processo, che normalmente ne causa la terminazione immediata.
È pertanto importante capire come viene strutturata \index{memoria~virtuale}
\textsl{la memoria virtuale} di un processo. Essa viene divisa in
automaticamente il codice necessario, seguendo quella che viene chiamata
una \textit{calling convention}; quella standard usata con il C ed il C++
è detta \textit{cdecl} e prevede che gli argomenti siano caricati nello
- stack dal chiamante da destra a sinistra, e che si il chiamante stesso ad
- eseguire la ripulitura dello stack al ritorno della funzione, se ne
- possono però utilizzare di alternative (ad esempio nel pascal gli
- argomenti sono inseriti da sinistra a destra ed è compito del chiamato
- ripulire lo stack), in genere non ci si deve preoccupare di questo
- fintanto che non si mescolano funzioni scritte con linguaggi diversi.}
+ \textit{stack} dal chiamante da destra a sinistra, e che si il chiamante
+ stesso ad eseguire la ripulitura dello \textit{stack} al ritorno della
+ funzione, se ne possono però utilizzare di alternative (ad esempio nel
+ pascal gli argomenti sono inseriti da sinistra a destra ed è compito del
+ chiamato ripulire lo \textit{stack}), in genere non ci si deve preoccupare
+ di questo fintanto che non si mescolano funzioni scritte con linguaggi
+ diversi.}
La dimensione di questo segmento aumenta seguendo la crescita dello
\itindex{stack} \textit{stack} del programma, ma non viene ridotta quando
\begin{figure}[htb]
\centering
- \includegraphics[height=12cm]{img/memory_layout}
+% \includegraphics[height=12cm]{img/memory_layout}
+ \begin{tikzpicture}
+ \draw (0,0) rectangle (4,1);
+ \draw (2,0.5) node {text};
+ \draw (0,1) rectangle (4,2.5);
+ \draw (2,1.75) node {dati inizializzati};
+ \draw (0,2.5) rectangle (4,5);
+ \draw (2,3.75) node {dati non inizializzati};
+ \draw (0,5) rectangle (4,9);
+ \draw[dashed] (0,6) -- (4,6);
+ \draw[dashed] (0,8) -- (4,8);
+ \draw (2,5.5) node {heap};
+ \draw (2,8.5) node {stack};
+ \draw [->] (2,6) -- (2,6.5);
+ \draw [->] (2,8) -- (2,7.5);
+ \draw (0,9) rectangle (4,10);
+ \draw (2,9.5) node {environment};
+ \draw (4,0) node [anchor=west] {\texttt{0x08000000}};
+ \draw (4,5) node [anchor=west] {\texttt{0x08xxxxxx}};
+ \draw (4,9) node [anchor=west] {\texttt{0xC0000000}};
+ \end{tikzpicture}
\caption{Disposizione tipica dei segmenti di memoria di un processo.}
\label{fig:proc_mem_layout}
\end{figure}
uso una versione meno efficiente delle funzioni suddette, che però è più
tollerante nei confronti di piccoli errori come quello di chiamate doppie a
\func{free}. In particolare:
-\begin{itemize*}
+\begin{itemize}
\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});
\item se è posta a 2 viene chiamata \func{abort}, che in genere causa
l'immediata conclusione del programma.
-\end{itemize*}
+\end{itemize}
Il problema più comune e più difficile da risolvere che si incontra con le
funzioni di allocazione è quando non viene opportunamente liberata la memoria
\textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche
molto complesse riguardo l'allocazione della memoria.
-
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
problemi di \itindex{memory~leak} \textit{memory leak} descritti in
precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
\textit{stack} della funzione corrente. La sintassi è identica a quella di
\func{malloc}, il suo prototipo è:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
- Alloca \param{size} byte nello stack.
+ Alloca \param{size} byte nello \textit{stack}.
- \bodydesc{La funzione restituisce il puntatore alla zona di memoria allocata
- in caso di successo e \val{NULL} in caso di fallimento, nel qual caso
- \var{errno} assumerà il valore \errval{ENOMEM}.}
+ \bodydesc{La funzione restituisce il puntatore alla zona di memoria
+ allocata.}
\end{prototype}
La funzione alloca la quantità di memoria (non inizializzata) richiesta
non può essere usata nella lista degli argomenti di una funzione, perché lo
spazio verrebbe allocato nel mezzo degli stessi.
-% Questo è riportato solo dal manuale delle glibc, nelle pagine di manuale non c'è
-% traccia di tutto ciò
-%
-%Inoltre se si
-%cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma un
-%segnale di \textit{segment violation} analogo a quello che si avrebbe da una
-%ricorsione infinita.
-% TODO inserire più informazioni su alloca come da man page
-
-
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
Questo è lo stesso problema che si può avere con le variabili automatiche, su
cui torneremo in sez.~\ref{sec:proc_auto_var}.
+Infine non esiste un modo di sapere se l'allocazione ha avuto successo, la
+funzione infatti viene realizzata inserendo del codice \textit{inline} nel
+programma\footnote{questo comporta anche il fatto che non è possibile
+ sostituirla con una propria versione o modificarne il comportamento
+ collegando il proprio programma con un'altra libreria.} che si limita a
+modificare il puntatore nello \itindex{stack} \textit{stack} e non c'è modo di
+sapere se se ne sono superate le dimensioni, per cui in caso di fallimento
+nell'allocazione il comportamento del programma può risultare indefinito,
+dando luogo ad una \itindex{segment~violation} \textit{segment violation} la
+prima volta che cercherà di accedere alla memoria non effettivamente
+disponibile.
Le due funzioni seguenti\footnote{le due funzioni sono state definite con BSD
- 4.3, non fanno parte delle librerie standard del C e mentre sono state
- esplicitamente escluse dallo standard POSIX.} 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 funzioni di allocazione della memoria.
-La prima funzione è \funcd{brk}, ed il suo prototipo è:
+ 4.3, sono marcate obsolete in SUSv2 e non fanno parte delle librerie
+ standard del C e mentre sono state esplicitamente rimosse dallo standard
+ POSIX/1-2001.} 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
+funzioni di allocazione della memoria. Per poterle utilizzare è necessario
+definire una della macro di funzionalità (vedi
+sez.~\ref{sec:intro_gcc_glibc_std}) fra \macro{\_BSD\_SOURCE},
+\macro{\_SVID\_SOURCE} e \macro{\_XOPEN\_SOURCE} (ad un valore maggiore o
+ugiale di 500). 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.
- \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}.}
\end{prototype}
-La funzione è un'interfaccia diretta all'omonima system call ed imposta
-l'indirizzo finale del \index{segmento!dati} segmento dati di un processo
-all'indirizzo specificato da \param{end\_data\_segment}. Quest'ultimo deve
-essere un valore ragionevole, ed inoltre la dimensione totale del segmento non
-deve comunque eccedere un eventuale limite (si veda
-sez.~\ref{sec:sys_resource_limit}) imposto sulle dimensioni massime dello
-spazio dati del processo.
-
-Una seconda funzione per la manipolazione delle dimensioni
+La funzione è un'interfaccia all'omonima system call ed imposta l'indirizzo
+finale del \index{segmento!dati} segmento dati di un processo all'indirizzo
+specificato da \param{end\_data\_segment}. Quest'ultimo deve essere un valore
+ragionevole, ed inoltre la dimensione totale del segmento non deve comunque
+eccedere un eventuale limite (si veda sez.~\ref{sec:sys_resource_limit})
+imposto sulle dimensioni massime dello spazio dati del processo.
+
+Il valore di ritorno della funzione fa riferimento alla versione fornita dalle
+\acr{glibc}, in realtà in Linux la \textit{system call} corrispondente
+restituisce come valore di ritorno il nuovo valore della fine del
+\index{segmento!dati} segmento dati in caso di successo e quello corrente in
+caso di fallimento, è la funzione di interfaccia usata dalle \acr{glibc} che
+fornisce i valori di ritorno appena descritti, questo può non accadere se si
+usano librerie diverse.
+
+Una seconda funzione per la manipolazione diretta delle dimensioni
\index{segmento!dati} del segmento dati\footnote{in questo caso si tratta
soltanto di una funzione di libreria, e non di una system call.} è
\funcd{sbrk}, ed il suo prototipo è:
\funcdecl{int munlock(const void *addr, size\_t len)}
Rimuove il blocco della paginazione su un intervallo di memoria.
- \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 in
+ \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ in
caso di errore, nel qual caso \var{errno} assumerà uno dei
valori seguenti:
\begin{errlist}
\itindend{memory~locking}
-% TODO documentare \func{madvise}
-% TODO documentare \func{mincore}
+\index{memoria~virtuale|)}
-\index{memoria~virtuale|)}
+\subsection{Gestione avanzata dell'allocazione della memoria}
+\label{sec:proc_memory_adv_management}
+
+La trattazione delle funzioni di allocazione di sez.~\ref{sec:proc_mem_alloc}
+si è limitata a coprire le esigenze generiche di un programma, in cui non si
+hanno dei requisiti specifici e si lascia il controllo delle modalità di
+allocazione alle funzioni di libreria. Tuttavia esistono una serie di casi in
+cui può essere necessario avere un controllo più dettagliato delle modalità
+con cui la memoria viene allocata; nel qual caso potranno venire in aiuto le
+funzioni trattate in questa sezione.
+
+Le prime funzioni che tratteremo sono quelle che consentono di richiedere di
+allocare un blocco di memoria ``\textsl{allineato}'' ad un multiplo una certa
+dimensione. Questo tipo di esigenza emerge usualmente quando si devono
+allocare dei buffer da utilizzare per eseguire dell'I/O diretto su dispositivi
+a blocchi. In questo caso infatti il trasferimento di dati viene eseguito per
+blocchi di dimensione fissa, ed è richiesto che l'indirizzo di partenza del
+buffer sia un multiplo intero di questa dimensione, usualmente 512 byte. In
+tal caso l'uso di \func{malloc} non è sufficiente, ed occorre utilizzare una
+funzione specifica.
+
+Tradizionalmente per rispondere a questa esigenza sono state crate due
+funzioni diverse, \funcd{memalign} e \funcd{valloc}, oggi obsolete; i
+rispettivi prototipi sono:
+\begin{functions}
+ \headdecl{malloc.h}
+
+ \funcdecl{void *valloc(size\_t size)} Alloca un blocco di memoria allineato
+ alla dimensione di una pagina di memoria.
+
+ \funcdecl{void *memalign(size\_t boundary, size\_t size)}
+ Alloca un blocco di memoria allineato ad un multiplo di \param{boundary}.
+
+ \bodydesc{Entrambe le funzioni ritornano un puntatore al blocco di memoria
+ allocato in caso di successo e \val{NULL} in caso di errore, nel qual
+ caso \var{errno} assumerà uno dei valori seguenti:
+ \begin{errlist}
+ \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'allocazione.
+ \item[\errcode{EINVAL}] \param{boundary} non è multiplo di due.
+ \end{errlist}
+}
+\end{functions}
+
+Le funzioni restituiscono il puntatore al buffer di memoria allocata, che per
+\func{memalign} sarà un multiplo di \param{boundary} mentre per \func{valloc}
+un multiplo della dimensione di una pagina di memoria. Nel caso della versione
+fornita dalle \acr{glibc} la memoria allocata con queste funzioni deve essere
+liberata con \func{free}.
+Nessuna delle due funzioni ha una chiara standardizzazione (nessuna delle due
+compare in POSIX.1), ed inoltre ci sono indicazione discordi sui file che ne
+contengono la definizione;\footnote{secondo SUSv2 \func{valloc} è definita in
+ \texttt{stdlib.h}, mentre sia le \acr{glibc} che le precedenti \acr{libc4} e
+ \acr{lic5} la dichiarano in \texttt{malloc.h}, lo stesso vale per
+ \func{memalign} che in alcuni sistemi è dichiarata in \texttt{stdlib.h}.}
+per questo motivo il loro uso è sconsigliato, essendo state sostituite dalla
+nuova \funcd{posix\_memalign}, che è stata standardizzata in POSIX.1d; il suo
+prototipo è:
-% \subsection{Gestione avanzata dell'allocazione della memoria}
-% \label{sec:proc_mem_malloc_custom}
+% TODO documentare \func{madvise}
+% TODO documentare \func{mincore}
% TODO: trattare le funzionalità avanzate di \func{malloc}
% TODO: trattare \func{memalign}
% TODO: trattare \func{valloc}
riconoscendo le possibili opzioni segnalate con \param{optstring}.
\bodydesc{Ritorna il carattere che segue l'opzione, \cmd{':'} se manca un
- parametro all'opzione, \cmd{'?'} se l'opzione è sconosciuta, e -1 se non
+ parametro all'opzione, \cmd{'?'} se l'opzione è sconosciuta, e $-1$ se non
esistono altre opzioni.}
\end{prototype}
stringa di opzioni avrebbe dovuto contenere \texttt{"r:m"}.
La modalità di uso di \func{getopt} è pertanto quella di chiamare più volte la
-funzione all'interno di un ciclo, fintanto che essa non ritorna il valore -1
+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
effettua il riordinamento del vettore \param{argv}.
-\subsection{Opzioni in formato esteso}
-\label{sec:proc_opt_extended}
-
-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}.
-
-(NdA: questa parte verrà inserita in seguito).
-% TODO opzioni in formato esteso
-
\subsection{Le variabili di ambiente}
\label{sec:proc_environ}
\funcdecl{int putenv(char *string)} Aggiunge la stringa \param{string}
all'ambiente.
- \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 per un
+ \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ per un
errore, che è sempre \errval{ENOMEM}.}
\end{functions}
\noindent la terza, \funcd{unsetenv}, serve a cancellare una variabile di
``\textsl{sicura}'' da zero.
+\subsection{Opzioni in formato esteso}
+\label{sec:proc_opt_extended}
+
+Oltre alla modalità ordinaria di gestione delle opzioni trattata in
+sez.~\ref{sec:proc_opt_handling} le \acr{glibc} forniscono una modalità
+alternativa costituita dalle cosiddette \textit{long-options}, che consente di
+esprimere le opzioni in una forma più descrittiva che nel caso più generale è
+qualcosa del tipo di ``\texttt{-{}-option-name=parameter}''.
+
+(NdA: questa parte verrà inserita in seguito).
+
+% TODO opzioni in formato esteso
+
+
+
\section{Problematiche di programmazione generica}
\label{sec:proc_gen_prog}
% LocalWords: SUCCESS FAILURE void atexit stream fclose unistd descriptor init
% LocalWords: SIGCHLD wait function glibc SunOS arg argp execve fig high kb Mb
% LocalWords: memory alpha swap table printf Unit MMU paging fault SIGSEGV BSS
-% LocalWords: multitasking segmentation text segment NULL Block Started Symbol
+% LocalWords: multitasking text segment NULL Block Started Symbol
% LocalWords: heap stack calling convention size malloc calloc realloc nmemb
% LocalWords: ENOMEM ptr uClib cfree error leak smartpointers hook Dmalloc brk
% LocalWords: Gray Watson Electric Fence Bruce Perens sbrk longjmp SUSv BSD ap