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
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
\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
attraverso il valore di ritorno. È buona norma seguire questa pratica anche
nella programmazione normale.
-
Talvolta però è necessario che la funzione possa restituire indietro alla
funzione chiamante un valore relativo ad uno dei suoi parametri. Per far
questo si usa il cosiddetto \textit{value result argument}, si passa cioè,
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
+ 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
-\type{char} o \type{short} (con segno o meno). Una restrizione ulteriore di
+\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
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 una macro ulteriore 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
variabile di argomenti è che non esiste un modo generico che permetta di
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}
\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,
+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
-annidate occorre usare quello che viene chiamato un salto \textsl{non-locale};
-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 è:
-
+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 da \cite{glibc}, è quello di un programma nel
+cui corpo principale in cui viene letto un input del quale viene eseguita
+attraverso una serie di funzioni di analisi una scansione dei contenuti da cui
+ottenere 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 nell'input può accadere
+all'interno di funzioni profondamente annidate l'una nell'altra. In questo
+caso si dovrebbe per ciascuna fase dover gestire tutta la casistica del
+passaggio all'indietro di tutti gli errori rilevabili dalle funzioni usate
+nelle fasi successive, mentre sarebbe molto più comodo poter tornare
+direttamente al ciclo di lettura principale, scartando l'input come
+errato.\footnote{a meno che, come precisa \cite{glibc}, alla chiusura di
+ ciascuna fase non siano associate operazioni di pulizia specifiche (come
+ deallocazioni, chiusure di file, ecc.), che non potrebbero essere eseguite
+ con un salto non-locale.}
+
+Tutto ciò può essere realizzato 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 è:
\begin{functions}
\headdecl{setjmp.h}
\funcdecl{void setjmp(jmp\_buf env)}
Salva il contesto dello stack in \param{env} per un successivo uso da parte
- di \func{longjmp}. Il contesto viene invalidato se la routine che ha
- chiamato \func{setjmp} ritorna.
-
+ di \func{longjmp}.
+
\bodydesc{La funzione ritorna zero quando è chiamata direttamente e un
valore diverso da zero quando ritorna da una chiamata di \func{longjmp}
che usa il contesto salvato in precedenza.}
\end{functions}
-
-Per poter effettuare un salto non locale si usa la funzione \func{longjmp}; il
-suo prototipo è:
+Quando si esegue la funzione il contesto viene salvato in appositi oggetti (di
+tipo \type{jmp\_buf}), passati come primo argomento alla funzione, in genere
+questi vengono definiti come variabili globali in modo da poter essere visti
+in tutte le funzioni del programma.
+
+Quando viene eseguita direttamente la funzione ritorna sempre zero, un valore
+diverso da zero viene restituito solo quando il ritorno è dovuto ad una
+chiamata di \func{longjmp} in un'altra parte del programma. Si tenga conto che
+il contesto salvato in \param{env} viene invalidato se la routine che ha
+chiamato \func{setjmp} ritorna, nel qual caso l'uso di \func{longjmp} può
+comportare conseguenze imprevedibili (e di norma fatali per il processo).
+
+Come accennato per effettuare un salto non-locale ad un punto precedentemente
+stabilito con \func{setjmp} si usa la funzione \func{longjmp}; il suo
+prototipo è:
\begin{functions}
\headdecl{setjmp.h}
\funcdecl{void longjmp(jmp\_buf env, int val)}
- Ripristina il contesto dello stack salvato dall'ultima chiamata di
- \func{setjmp} con l'argomento \param{env}. Il programma prosegue dal ritorno
- di \func{setjmp} con un valore \param{val}. Il valore di \param{val} deve
- essere diverso da zero, se viene specificato 0 sarà usato 1 al suo posto.
-
+ Ripristina il contesto dello stack salvato nell'ultima chiamata di
+ \func{setjmp} con l'argomento \param{env}.
+
\bodydesc{La funzione non ritorna.}
\end{functions}
+Dopo l'esecuzione della funzione programma prosegue dal codice successivo al
+ritorno della \func{setjmp} con cui si era salvato \param{env}, che restituirà
+il valore \param{val} invece di zero. Il valore di \param{val} specificato
+nella chiamata deve essere diverso da zero, se si è specificato 0 sarà
+comunque restituito 1 al suo posto.
+
+In sostanza un \func{longjmp} è analogo ad un \code{return}, solo che invece
+di ritornare alla riga successiva della funzione chiamante, il programma
+ritorna alla posizione della relativa \func{setjmp}, ed il ritorno può essere
+effettuato anche attraverso diversi livelli di funzioni annidate.
+
+L'implementazione di queste funzioni comporta alcune restrizioni dato che esse
+interagiscono direttamente con la gestione dello stack ed il funzionamento del
+compilatore stesso. In particolare \func{setjmp} è implementata con una macro,
+pertanto non si può cercare di ottenerne l'indirizzo, ed inoltre delle
+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}).
+\item come operando per un operatore di uguaglianza o confronto in una
+ espressione di controllo di un comando condizionale, di selezione o di
+ iterazione.
+\item come operando per l'operatore di negazione (\code{!}) in una espressione
+ 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}.
+
+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 \code{register}) sono in
+genere indeterminati.
+
+Quello che succede infatti è che i valori delle variabili che sono tenute in
+memoria manterranno il valore avuto al momento della chiamata di
+\func{longjmp}, mentre quelli tenuti nei registri del processore (che nella
+chiamata ad un'altra funzioni vengono salvati nel contesto nello stack)
+torneranno al valore avuto al momento della chiamata di \func{setjmp}; per
+questo quando si vuole avere un comportamento coerente si può bloccare
+l'ottimizzazione che porta le variabili nei registri dichiarandole tutte come
+\code{volatile}.
+
+
%%% Local Variables:
%%% mode: latex