X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=e3a4774786115eb7561fadeb0e0d914856dc4385;hp=935f34e5f6c67f14f4b7d3dc87781408e0e4345d;hb=d7305d300866c1e6909dd23743060632b3718178;hpb=2bb235e9ba8e8d532251205d30b82455dc119894 diff --git a/process.tex b/process.tex index 935f34e..e3a4774 100644 --- a/process.tex +++ b/process.tex @@ -23,9 +23,9 @@ programma: si possono avere pi 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 - \textit{multi-thread}, ma sulla gestione dei \textit{thread} in Linux - torneremo più avanti}. +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.} \subsection{La funzione \func{main}} @@ -50,10 +50,10 @@ Lo standard ISO C specifica che la funzione \func{main} pu 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 @@ -108,7 +108,7 @@ uno stato di uscita uguale a zero, che verrebbe interpretato come un successo. 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}} @@ -211,7 +211,7 @@ stream aperti, infine verr \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}). @@ -253,11 +253,12 @@ esecuzione, e le varie funzioni utilizzabili per la sua gestione. 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 @@ -286,15 +287,15 @@ gestione della memoria (la \textit{Memory Management Unit} del processore). 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 @@ -305,8 +306,8 @@ a tempi molto pi 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} @@ -318,9 +319,9 @@ tentativo di accedere ad un indirizzo non allocato 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} +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 @@ -341,7 +342,7 @@ programma C viene suddiviso nei seguenti segmenti: \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 @@ -380,7 +381,10 @@ programma C viene suddiviso nei seguenti segmenti: 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. @@ -492,13 +496,13 @@ La funzione \func{realloc} si usa invece per cambiare (in genere aumentare) la 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 @@ -538,15 +542,18 @@ routine di allocazione 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 @@ -656,10 +663,10 @@ 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 @@ -839,7 +846,7 @@ questo meccanismo \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 @@ -1125,7 +1132,7 @@ ambiente; il suo prototipo \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 @@ -1145,7 +1152,7 @@ invece esiste il suo valore sar 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 @@ -1173,7 +1180,7 @@ problematiche generali che possono emergere nella programmazione e di quali 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} @@ -1207,7 +1214,6 @@ informazioni a riguardo dei risultati vengono passate alla routine chiamante 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è, @@ -1255,13 +1261,13 @@ del vettore \var{argv} passato al nuovo processo). Lo standard ISO C richiede 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 @@ -1284,7 +1290,7 @@ in generale 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à. @@ -1330,12 +1336,12 @@ stack all'indirizzo dove sono stati salvati i parametri, 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 un'ulteriore macro 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}. @@ -1354,9 +1360,8 @@ In Linux gli argomenti dello stesso tipo sono passati allo stesso modo, sia 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 @@ -1388,56 +1393,131 @@ Per questo una delle regole fondamentali della programmazione in C 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 -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