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 sulla gestione dei \textit{thread} in Linux
- torneremo più avanti.}
+ \textit{multi-thread}, ma la gestione dei \textit{thread} in Linux sarà
+ trattata a parte.}
\subsection{La funzione \func{main}}
argomenti o prendere due argomenti che rappresentano gli argomenti passati da
linea di comando, in sostanza un prototipo che va sempre bene è il seguente:
\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
- int main (int argc, char *argv[])
+ int main (int argc, char *argv[])
\end{lstlisting}
-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 parametro, \var{char
*envp[]}, che fornisce l'\textsl{ambiente} (vedi \secref{sec:proc_environ})
del programma; questa forma però non è prevista dallo standard POSIX.1 per cui
Un'esigenza comune che si incontra nella programmazione è quella di dover
effettuare una serie di operazioni di pulizia (ad esempio salvare dei dati,
-ripristinare dei settaggi, eliminare dei file temporanei, ecc.) prima della
-conclusione di un programma. In genere queste operazioni vengono fatte in
-un'apposita sezione del programma, ma quando si realizza una libreria diventa
-antipatico dover richiedere una chiamata esplicita ad una funzione di pulizia
-al programmatore che la utilizza.
+ripristinare delle impostazioni, eliminare dei file temporanei, ecc.) prima
+della conclusione di un programma. In genere queste operazioni vengono fatte
+in un'apposita sezione del programma, ma quando si realizza una libreria
+diventa antipatico dover richiedere una chiamata esplicita ad una funzione di
+pulizia al programmatore che la utilizza.
È invece molto meno soggetto ad errori, e completamente trasparente
all'utente, avere la possibilità di effettuare automaticamente la chiamata ad
programma.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- fallimento, \var{errno} non viene settata.}
+ fallimento, \var{errno} non viene modificata.}
\end{prototype}
\noindent la funzione richiede come argomento l'indirizzo della opportuna
funzione di pulizia da chiamare all'uscita, che non deve prendere argomenti e
rispetto a quello di registrazione.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
- fallimento, \var{errno} non viene settata.}
+ fallimento, \var{errno} non viene modificata.}
\end{prototype}
In questo caso la funzione da chiamare prende due parametri, il primo dei
\label{sec:proc_term_conclusion}
Data l'importanza dell'argomento è opportuno sottolineare ancora una volta che
-in un sistema unix l'unico modo in cui un programma può essere eseguito dal
+in un sistema Unix l'unico modo in cui un programma può essere eseguito dal
kernel è attraverso la chiamata alla system call \func{execve} (o attraverso
una delle funzioni della famiglia \func{exec} che vedremo in
\secref{sec:proc_exec}).
Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli
di basso livello dipendono spesso in maniera diretta dall'architettura
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
- 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.}
+la cosiddetta \textsl{memoria virtuale}\index{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 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.}
Come accennato in \capref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
Poiché in genere la memoria fisica è solo una piccola frazione della memoria
virtuale, è necessario un meccanismo che permetta di trasferire le pagine che
servono dal supporto su cui si trovano in memoria, eliminando quelle che non
-servono. Questo meccanismo è detto \textit{paging}, ed è uno dei compiti
-principali del kernel.
+servono. Questo meccanismo è detto \textsl{paginazione}\index{paginazione} (o
+\textit{paging}), ed è uno dei compiti principali del kernel.
Quando un processo cerca di accedere ad una pagina che non è nella memoria
-reale, avviene quello che viene chiamato un \textit{page fault}; l'hardware di
-gestione della memoria genera un'interruzione e passa il controllo al kernel
-il quale sospende il processo e si incarica di mettere in RAM la pagina
-richiesta (effettuando tutte le operazioni necessarie per reperire lo spazio
-necessario), per poi restituire il controllo al processo.
+reale, avviene quello che viene chiamato un
+\textit{page fault}\index{page fault};
+l'hardware di gestione della memoria genera un'interruzione e passa
+il controllo al kernel il quale sospende il processo e si incarica di mettere
+in RAM la pagina richiesta (effettuando tutte le operazioni necessarie per
+reperire lo spazio necessario), per poi restituire il controllo al processo.
Dal punto di vista di un processo questo meccanismo è completamente
trasparente, e tutto avviene come se tutte le pagine fossero sempre
Normalmente questo è il prezzo da pagare per avere un multitasking reale, ed
in genere il sistema è molto efficiente in questo lavoro; quando però ci siano
esigenze specifiche di prestazioni è possibile usare delle funzioni che
-permettono di bloccare il meccanismo del paging e mantenere fisse delle pagine
-in memoria (vedi \ref{sec:proc_mem_lock}).
+permettono di bloccare il meccanismo della paginazione e mantenere fisse delle
+pagine in memoria (vedi \ref{sec:proc_mem_lock}).
\subsection{La struttura della memoria di un processo}
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 \textit{page fault} mandando un
-segnale \macro{SIGSEGV} al processo, che normalmente ne causa la terminazione
-immediata.
+virtuale, il kernel risponde al relativo \textit{page fault}\index{page fault}
+mandando un segnale \macro{SIGSEGV} al processo, che normalmente ne causa la
+terminazione immediata.
-È pertanto importante capire come viene strutturata la memoria virtuale di un
-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:
+È pertanto importante capire come viene strutturata \textsl{la memoria
+ virtuale}\index{page fault} di un 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:
\begin{enumerate}
\item Il segmento di testo o \textit{text segment}. Contiene il codice del
\begin{figure}[htb]
\centering
\includegraphics[width=5cm]{img/memory_layout}
- \caption{Disposizione tipica dei segmenti di memoria di un processo}
+ \caption{Disposizione tipica dei segmenti di memoria di un processo.}
\label{fig:proc_mem_layout}
\end{figure}
La funzione restituisce il puntatore alla zona di memoria allocata in caso
di successo e \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} viene settata a \macro{ENOMEM}.
+ \var{errno} assumerà il valore \macro{ENOMEM}.
\funcdecl{void *malloc(size\_t size)}
Alloca \var{size} byte nello heap. La memoria non viene inizializzata.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
di successo e \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} viene settata a \macro{ENOMEM}.
+ \var{errno} assumerà il valore \macro{ENOMEM}.
\funcdecl{void *realloc(void *ptr, size\_t size)}
Cambia la dimensione del blocco allocato all'indirizzo \var{ptr}
portandola a \var{size}.
La funzione restituisce il puntatore alla zona di memoria allocata in caso
di successo e \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} viene settata a \macro{ENOMEM}.
+ \var{errno} assumerà il valore \macro{ENOMEM}.
\funcdecl{void free(void *ptr)}
Disalloca lo spazio di memoria puntato da \var{ptr}.
\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
-torneremo in \secref{sec:xxx_advanced}) che permettono di tracciare le
-allocazioni e le disallocazione, 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).
+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 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).
\subsection{La funzione \func{alloca}}
La funzione restituisce il puntatore alla zona di memoria allocata in caso
di successo e \macro{NULL} in caso di fallimento, nel qual caso
- \var{errno} viene settata a \macro{ENOMEM}.
+ \var{errno} assumerà il valore \macro{ENOMEM}.
\end{prototype}
\noindent ma in questo caso non è più necessario liberare la memoria (e quindi
non esiste un analogo della \func{free}) in quanto essa viene rilasciata
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 man page non c'è
+% Questo è riportato solo dal manuale delle glibc, nelle pagine di manuale non c'è
% traccia di tutto ciò
%
%Inoltre se si
\var{end\_data\_segment}.
La funzione restituisce 0 in caso di successo e -1 in caso di
- fallimento, nel qual caso \var{errno} viene settata a \macro{ENOMEM}.
+ fallimento, nel qual caso \var{errno} assumerà il valore \macro{ENOMEM}.
\funcdecl{void *sbrk(ptrdiff\_t increment)} Incrementa lo spazio dati di un
programma di \var{increment}. Un valore zero restituisce l'attuale posizione
La funzione restituisce il puntatore all'inizio della nuova zona di memoria
allocata in caso di successo e \macro{NULL} in caso di fallimento, nel qual
- caso \macro{errno} viene settata a \macro{ENOMEM}.
+ caso \macro{errno} assumerà il valore \macro{ENOMEM}.
\end{functions}
\noindent in genere si usa \func{sbrk} con un valore zero per ottenere
l'attuale posizione della fine del segmento dati.
% \label{sec:proc_mem_malloc_custom}
-\subsection{Il controllo della memoria virtuale}
+\subsection{Il controllo della memoria virtuale\index{memoria virtuale}}
\label{sec:proc_mem_lock}
-Come spiegato in \secref{sec:proc_mem_gen} il kernel gestisce la memoria in
-maniera trasparente ai processi, decidendo quando rimuovere pagine dalla
-memoria per metterle nello swap, sulla base dell'utilizzo corrente da parte
-dei vari processi.
+Come spiegato in \secref{sec:proc_mem_gen} il kernel gestisce la memoria
+virtuale in maniera trasparente ai processi, decidendo quando rimuovere pagine
+dalla memoria per metterle nello swap, sulla base dell'utilizzo corrente da
+parte dei vari processi.
Nell'uso comune un processo non deve preoccuparsi di tutto ciò, in quanto il
-meccanismo della paginazione riporta in RAM, ed in maniera trasparente, tutte
-le pagine che gli occorrono; esistono però esigenze particolari in cui non si
-vuole che questo meccanismo si attivi. In generale i motivi per cui si possono
-avere di queste necessità sono due:
+meccanismo della paginazione\index{paginazione} riporta in RAM, ed in maniera
+trasparente, tutte le pagine che gli occorrono; esistono però esigenze
+particolari in cui non si vuole che questo meccanismo si attivi. In generale i
+motivi per cui si possono avere di queste necessità sono due:
\begin{itemize}
\item \textsl{La velocità}. Il processo della paginazione è trasparente solo
se il programma in esecuzione non è sensibile al tempo che occorre a
tutti i suoi \textit{memory lock}.
I \textit{memory lock} non sono ereditati dai processi figli.\footnote{ma
- siccome Linux usa il \textit{copy on write} (vedi \secref{sec:proc_fork})
- gli indirizzi virtuali del figlio sono mantenuti sullo stesso segmento di
- RAM del padre, quindi fintanto che un figlio non scrive su un segmento, può
- usufruire del memory lock del padre.} Siccome la presenza di un
-\textit{memory lock} riduce la memoria disponibile al sistema, con un impatto
-su tutti gli altri processi, solo l'amministratore ha la capacità di bloccare
-una pagina. Ogni processo può però sbloccare le pagine relative alla propria
-memoria.
+ siccome Linux usa il \textit{copy on write}\index{copy on write} (vedi
+ \secref{sec:proc_fork}) gli indirizzi virtuali del figlio sono mantenuti
+ sullo stesso segmento di RAM del padre, quindi fintanto che un figlio non
+ scrive su un segmento, può usufruire del memory lock del padre.} Siccome la
+presenza di un \textit{memory lock} riduce la memoria disponibile al sistema,
+con un impatto su tutti gli altri processi, solo l'amministratore ha la
+capacità di bloccare una pagina. Ogni processo può però sbloccare le pagine
+relative alla propria memoria.
Il sistema pone dei limiti all'ammontare di memoria di un processo che può
essere bloccata e al totale di memoria fisica che può dedicare a questo, lo
\bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 in
- caso di errore, nel qual caso \var{errno} è settata ad uno dei
+ caso di errore, nel qual caso \var{errno} assumerà uno dei
valori seguenti:
\begin{errlist}
\item[\macro{ENOMEM}] alcuni indirizzi dell'intervallo specificato non
In ogni caso un processo real-time che deve entrare in una sezione critica
deve provvedere a riservare memoria sufficiente prima dell'ingresso, per
-scongiurare in partenza un eventuale page fault causato dal meccanismo di
-\textit{copy on write}. Infatti se nella sezione critica si va ad utilizzare
-memoria che non è ancora stata riportata in RAM si potrebbe avere un page
-fault durante l'esecuzione della stessa, con conseguente rallentamento
-(probabilmente inaccettabile) dei tempi di esecuzione.
+scongiurare in partenza un eventuale page fault\index{page fault} causato dal
+meccanismo di \textit{copy on write}\index{copy on write}. Infatti se nella
+sezione critica si va ad utilizzare memoria che non è ancora stata riportata
+in RAM si potrebbe avere un page fault durante l'esecuzione della stessa, con
+conseguente rallentamento (probabilmente inaccettabile) dei tempi di
+esecuzione.
In genere si ovvia a questa problematica chiamando una funzione che ha
allocato una quantità sufficientemente ampia di variabili automatiche, in modo
(il cosiddetto \textit{parsing}) per individuare le parole che la compongono,
ciascuna delle quali viene considerata un parametro. Di norma per individuare
le parole viene usato come carattere di separazione lo spazio o il tabulatore,
-ma il comportamento è modificabile attraverso il settaggio della variabile di
-ambiente \cmd{IFS}.
+ma il comportamento è modificabile attraverso l'impostazione della variabile
+di ambiente \cmd{IFS}.
\begin{figure}[htb]
\centering
\subsection{La gestione delle opzioni}
\label{sec:proc_opt_handling}
-In generale un programma unix riceve da linea di comando sia gli argomenti che
+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 \var{argv} che inizia con \texttt{-} e che non sia un
singolo \texttt{-} o un \texttt{--} viene considerato un'opzione. In genere
così che alla fine della scansione gli elementi che non sono opzioni sono
spostati in coda al vettore. Oltre a questa esistono altre due modalità di
gestire gli elementi di \var{argv}; se \var{optstring} inizia con il carattere
-\texttt{'+'} (o è settata la variabile di ambiente \macro{POSIXLY\_CORRECT})
+\texttt{'+'} (o è impostata la variabile di ambiente \macro{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 opzioni e argomenti, ma se li aspetta in un ordine definito, si
\hline
\hline
\macro{USER} & $\bullet$ & $\bullet$ & $\bullet$ & Nome utente\\
- \macro{LOGNAME} & $\bullet$ & $\bullet$ & $\bullet$ & Nome utente\\
+ \macro{LOGNAME} & $\bullet$ & $\bullet$ & $\bullet$ & Nome di login\\
\macro{HOME} & $\bullet$ & $\bullet$ & $\bullet$ &
Directory base dell'utente\\
\macro{LANG} & $\bullet$ & $\bullet$ & $\bullet$ & Localizzazione\\
\macro{TERM} & $\bullet$ & $\bullet$ & $\bullet$ & Tipo di terminale\\
\macro{PAGER} & $\bullet$ & $\bullet$ & $\bullet$ & Programma per vedere i
testi\\
- \macro{EDITOR} & $\bullet$ & $\bullet$ & $\bullet$ & Editor di default\\
- \macro{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser di default\\
+ \macro{EDITOR} & $\bullet$ & $\bullet$ & $\bullet$ & Editor preferito\\
+ \macro{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser preferito\\
\hline
\end{tabular}
\caption{Variabili di ambiente più comuni definite da vari standard.}
Oltre a questa funzione di lettura, che è l'unica definita dallo standard ANSI
C, nell'evoluzione dei sistemi Unix ne sono state proposte altre, da
-utilizzare per settare e per cancellare le variabili di ambiente. Uno schema
+utilizzare per impostare e per cancellare le variabili di ambiente. Uno schema
delle funzioni previste nei vari standard e disponibili in Linux è riportato
in \ntab.
\headdecl{stdlib.h}
\funcdecl{int setenv(const char *name, const char *value, int overwrite)}
- Setta la variabile di ambiente \param{name} al valore \param{value}.
+ Imposta la variabile di ambiente \param{name} al valore \param{value}.
\funcdecl{int putenv(char *string)} Aggiunge la stringa \param{string}
all'ambiente.
La seconda funzione prende come parametro una stringa analoga quella
restituita da \func{getenv}, e sempre nella forma \var{NOME=valore}. Se la
variabile specificata non esiste la stringa sarà aggiunta all'ambiente, se
-invece esiste il suo valore sarà settato a quello specificato da
+invece esiste il suo valore sarà impostato a quello specificato da
\param{string}. Si tenga presente che, seguendo lo standard SUSv2, le
\acr{glibc} successive alla versione 2.1.2 aggiungono\footnote{il
comportamento è lo stesso delle vecchie \acr{libc4} e \acr{libc5}; nelle
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è,
normale pensare di poter effettuare questa operazione.
In generale però possono esistere anche realizzazioni diverse, per questo
-motivo \macro{va\_list} è definito come tipo opaco e non può essere assegnato
-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:
+motivo \macro{va\_list} è definito come \textsl{tipo opaco} e non può essere
+assegnato 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:
\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}.
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
stabilire quanti sono i parametri passati effettivamente in una chiamata.
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