ciascun processo vedrà la sua copia del codice (in realtà il kernel fa sì che
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
+tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma
\textit{multi-thread}, ma sulla gestione dei \textit{thread} in Linux
- torneremo più avanti}.
+ torneremo più avanti.}
\subsection{La funzione \func{main}}
In \file{stdlib.h} sono definite, seguendo lo standard POSIX, le due macro
\macro{EXIT\_SUCCESS} e \macro{EXIT\_FAILURE}, da usare sempre per specificare
lo stato di uscita di un processo. In Linux esse sono poste rispettivamente ai
-valori di tipo \type{int} 0 e 1.
+valori di tipo \ctyp{int} 0 e 1.
\subsection{Le funzioni \func{exit} e \func{\_exit}}
dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è
la cosiddetta \textsl{memoria virtuale} che consiste 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
+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}.
+ 2.4 ed il supporto per la \textit{high-memory} il limite è stato esteso.}
Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
\item Il segmento dei dati o \textit{data segment}. Contiene le variabili
globali (cioè quelle definite al di fuori di tutte le funzioni che
compongono il programma) e le variabili statiche (cioè quelle dichiarate con
- l'attributo \type{static}). Di norma è diviso in due parti.
+ l'attributo \ctyp{static}). Di norma è diviso in due parti.
La prima parte è il segmento dei dati inizializzati, che contiene le
variabili il cui valore è stato assegnato esplicitamente. Ad esempio
del chiamante (tipo il contenuto di alcuni registri della CPU). Poi la
funzione chiamata alloca qui lo spazio per le sue variabili locali: in
questo modo le funzioni possono essere chiamate ricorsivamente. Al ritorno
- della funzione lo spazio è automaticamente rilasciato.
+ della funzione lo spazio è automaticamente rilasciato. Al ritorno della
+ funzione lo spazio è automaticamente ripulito. La pulizia in C e C++ viene
+ fatta dal chiamante.\footnote{a meno che non sia stato specificato
+ l'utilizzo di una calling convention diversa da quella standard.}
La dimensione di questo segmento aumenta seguendo la crescita dello stack
del programma, ma non viene ridotta quando quest'ultimo si restringe.
dimensione di un'area di memoria precedentemente allocata, la funzione vuole
in ingresso il puntatore restituito dalla precedente chiamata ad una
\func{malloc} (se è passato un valore \macro{NULL} allora la funzione si
-comporta come \func{malloc}\footnote{questo è vero per Linux e
+comporta come \func{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 \func{realloc} anche per un puntatore liberato con
\func{free} purché non ci fossero state nel frattempo altre chiamate a
funzioni di allocazione, questa funzionalità è totalmente deprecata e non è
- consentita sotto Linux.}), ad esempio quando si deve far crescere la
+ 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 utilizza, altrimenti rialloca altrove
un blocco della dimensione voluta, copiandoci automaticamente il contenuto; lo
non più utilizzata, quello che in inglese viene chiamato \textit{memory-leak},
(cioè \textsl{perdita di memoria}).
-Un caso tipico che illustra il problema è quello in cui l'allocazione di una
-variabile viene fatta da una subroutine per un uso locale, ma la memoria non
-viene liberata; la funzione esce e la memoria resta allocata (fino alla
-terminazione del processo). Chiamate ripetute alla stessa subroutine
-continueranno ad allocarne ancora, causando a lungo andare un esaurimento
-della memoria disponibile e l'impossibilità di proseguire il programma. Il
-problema è che l'esaurimento che può avvenire in qualunque momento, e senza
-nessuna relazione con la subroutine che contiene l'errore, per questo motivo è
-sempre complesso trovare un \textit{memory leak}.
+Un caso tipico che illustra il problema è quello in cui in una subroutine si
+alloca della memoria per uso locale senza liberarla prima di uscire. La
+memoria resta così allocata fino alla terminazione del processo. Chiamate
+ripetute alla stessa subroutine continueranno ad effettuare altre allocazioni,
+causando a lungo andare un esaurimento della memoria disponibile (e la
+probabile l'impossibilità di proseguire l'esecuzione programma).
+
+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 subroutine
+che contiene l'errore. Per questo motivo è sempre molto difficile trovare un
+\textit{memory leak}.
Per ovviare a questi problemi l'implementazione delle routine di allocazione
delle \acr{glibc} mette a disposizione una serie di funzionalità (su cui
\end{functions}
\noindent questa funzione elimina ogni occorrenza della variabile specificata;
se essa non esiste non succede nulla. Non è prevista (dato che la funzione è
-\type{void}) nessuna segnalazione di errore.
+\ctyp{void}) nessuna segnalazione di errore.
Per modificare o aggiungere una variabile di ambiente si possono usare sia
\func{setenv} che \func{putenv}. La prima permette di specificare
seguendo il comportamento di BSD4.4; dato che questo può dar luogo a perdite
di memoria e non rispetta lo standard. Il comportamento è stato modificato a
partire dalle 2.1.2, eliminando anche, sempre in conformità a SUSv2,
- l'attributo \type{const} dal prototipo.} \param{string} alla lista delle
+ l'attributo \ctyp{const} dal prototipo.} \param{string} alla lista delle
variabili di ambiente; pertanto ogni cambiamento alla stringa in questione si
riflette automaticamente sull'ambiente, e quindi si deve evitare di passare a
questa funzione una variabile automatica (per evitare i problemi esposti in
precauzioni o accorgimenti occorre prendere per risolverle. Queste
problematiche non sono specifiche di sistemi unix-like o multitasking, ma
avendo trattato in questo capitolo il comportamento dei processi visti come
-entità a se stanti, le riportiamo qui.
+entità a sé stanti, le riportiamo qui.
\subsection{Il passaggio delle variabili e dei valori di ritorno}
inoltre che l'ultimo degli argomenti fissi sia di tipo
\textit{self-promoting}\footnote{il linguaggio C prevede che quando si
mescolano vari tipi di dati, alcuni di essi possano essere \textsl{promossi}
- per compatibilità; ad esempio i tipi \type{float} vengono convertiti
- automaticamente a \type{double} ed i \type{char} e gli \type{short} ad
- \type{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso
- a se stesso.} il che esclude array, puntatori a funzioni e interi di tipo
-\type{char} o \type{short} (con segno o meno). Un'ulteriore restrizione di
+ per compatibilità; ad esempio i tipi \ctyp{float} vengono convertiti
+ automaticamente a \ctyp{double} ed i \ctyp{char} e gli \ctyp{short} ad
+ \ctyp{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso
+ a sé stesso.} il che esclude array, puntatori a funzioni e interi di tipo
+\ctyp{char} o \ctyp{short} (con segno o meno). Una restrizione ulteriore di
alcuni compilatori è di non dichiarare l'ultimo parametro fisso come
-\type{register}.
+\ctyp{register}.
Una volta dichiarata la funzione il secondo passo è accedere ai vari parametri
quando la si va a definire. I parametri fissi infatti hanno un loro nome, ma
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
-otterranno dei valori indefiniti. Nel caso del \cmd{gcc} poi l'uso della macro
+otterranno dei valori indefiniti. Nel caso del \cmd{gcc} l'uso della macro
\macro{va\_end} è inutile, ma si consiglia di usarlo ugualmente per
compatibilità.
direttamente ad un altra variabile dello stesso tipo. Per risolvere questo
problema 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 standard} ha previsto un'ulteriore macro che permette di
-eseguire la copia di un puntatore alla lista degli argomenti:
+ in una bozza dello standard.} ha previsto una macro ulteriore che permette
+di eseguire la copia di un puntatore alla lista degli argomenti:
\begin{prototype}{stdarg.h}{void va\_copy(va\_list dest, va\_list src)}
Copia l'attuale valore \param{src} del puntatore alla lista degli argomenti
su \param{dest}.
che siano fissi sia che siano opzionali (alcuni sistemi trattano diversamente
gli opzionali), ma dato che il prototipo non può specificare il tipo degli
argomenti opzionali, questi verranno sempre promossi, pertanto nella ricezione
-dei medesimi occorrerà tenerne conto (ad esempio un \type{char} verrà visto da
-\macro{va\_arg} come \type{int}).
+dei medesimi occorrerà tenerne conto (ad esempio un \ctyp{char} verrà visto da
+\macro{va\_arg} come \ctyp{int}).
Uno dei problemi che si devono affrontare con le funzioni con un numero
all'uscita di una funzione non deve restare nessun riferimento alle variabili
locali; qualora sia necessario utilizzare variabili che possano essere viste
anche dalla funzione chiamante queste devono essere allocate esplicitamente, o
-in maniera statica (usando variabili di tipo \type{static} o \type{extern}), o
+in maniera statica (usando variabili di tipo \ctyp{static} o \ctyp{extern}), o
dinamicamente con una delle funzioni della famiglia \func{malloc}.
\subsection{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
-\code{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.
+varie istruzioni del linguaggio C; fra queste la più bistrattata è il
+\code{goto}, che viene deprecato in favore dei costrutti della programmazione
+strutturata, che rendono il codice più leggibile e mantenibile . Esiste però
+un caso in cui l'uso di questa istruzione porta all'implementazione più
+efficiente e chiara anche dal punto di vista della struttura del programma,
+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
questo viene fatto usando salvando il contesto dello stack nel punto in cui si
vuole tornare in caso di errore, e ripristinandolo quando l'occorrenza capita.
-
La funzione che permette di salvare il contesto dello stack è \func{setjmp},
il cui prototipo è: