X-Git-Url: https://gapil.gnulinux.it/gitweb/?a=blobdiff_plain;f=process.tex;h=b572ee39f7525aefd751c268de92669612a78721;hb=3dad79fd0c4b88a38359a513de64aad465b9f43b;hp=512e2d7b1e748c8800a2c86cd00a11a435f9eb5d;hpb=66e83c068629844f84fe4a0d44b382f756c9ef32;p=gapil.git diff --git a/process.tex b/process.tex index 512e2d7..b572ee3 100644 --- a/process.tex +++ b/process.tex @@ -43,29 +43,30 @@ tutti gli altri.\footnote{questo non Quando un programma viene lanciato il kernel esegue un'opportuna routine di avvio, usando il programma \cmd{ld-linux.so}. Questo programma prima carica -le librerie condivise che servono al programma, poi effettua il link dinamico -del codice e alla fine lo esegue. Infatti, a meno di non aver specificato il -flag \texttt{-static} durante la compilazione, tutti i programmi in Linux sono -incompleti e necessitano di essere \textit{linkati} alle librerie condivise -quando vengono avviati. La procedura è controllata da alcune variabili di -ambiente e dal contenuto di \file{/etc/ld.so.conf}. I dettagli sono riportati -nella man page di \cmd{ld.so}. +le librerie condivise che servono al programma, poi effettua il collegamento +dinamico del codice e alla fine lo esegue. Infatti, a meno di non aver +specificato il flag \texttt{-static} durante la compilazione, tutti i +programmi in Linux sono incompleti e necessitano di essere \textsl{collegati} +alle librerie condivise quando vengono avviati. La procedura è controllata da +alcune variabili di ambiente e dal contenuto di \file{/etc/ld.so.conf}. I +dettagli sono riportati nella man page di \cmd{ld.so}. Il sistema fa partire qualunque programma chiamando la funzione \func{main}; sta al programmatore chiamare così la funzione principale del programma da cui si suppone iniziare l'esecuzione; in ogni caso senza questa funzione lo stesso -\textit{linker} darebbe luogo ad errori. - -Lo standard ISO C specifica che la funzione \func{main} può non avere -argomenti o prendere due argomenti che rappresentano gli argomenti passati da -linea di comando, in sostanza un prototipo che va sempre bene è il seguente: +\textit{linker} (si chiama così il programma che effettua i collegamenti di +cui sopra) darebbe luogo ad errori. Lo standard ISO C specifica che la +funzione \func{main} può non avere argomenti o prendere due argomenti che +rappresentano gli argomenti passati da linea di comando, in sostanza un +prototipo che va sempre bene è il seguente: \includecodesnip{listati/main_def.c} -In realtà nei sistemi Unix esiste un'altro modo per definire la funzione -\func{main}, che prevede la presenza di un terzo parametro, \code{char - *envp[]}, che fornisce l'\textsl{ambiente} (vedi sez.~\ref{sec:proc_environ}) -del programma; questa forma però non è prevista dallo standard POSIX.1 per cui -se si vogliono scrivere programmi portabili è meglio evitarla. +In realtà nei sistemi Unix esiste un altro modo per definire la funzione +\func{main}, che prevede la presenza di un terzo argomento, \code{char + *envp[]}, che fornisce (vedi sez.~\ref{sec:proc_environ}) +l'\textsl{ambiente} del programma; questa forma però non è prevista dallo +standard POSIX.1 per cui se si vogliono scrivere programmi portabili è meglio +evitarla. \subsection{Come chiudere un programma} @@ -151,7 +152,7 @@ non vengono salvati e le eventuali funzioni registrate con \func{atexit} e La funzione chiude tutti i file descriptor appartenenti al processo (si tenga presente che questo non comporta il salvataggio dei dati bufferizzati degli -stream), fa sì che ogni figlio del processo sia ereditato da \cmd{init} (vedi +stream), fa sì che ogni figlio del processo sia adottato da \cmd{init} (vedi cap.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di uscita specificato in \param{status} che può essere raccolto usando la @@ -232,15 +233,15 @@ normalmente un programma \begin{figure}[htb] \centering - \includegraphics[width=14cm]{img/proc_beginend} + \includegraphics[width=9cm]{img/proc_beginend} \caption{Schema dell'avvio e della conclusione di un programma.} \label{fig:proc_prog_start_stop} \end{figure} Si ricordi infine che un programma può anche essere interrotto dall'esterno attraverso l'uso di un segnale (modalità di conclusione non mostrata in -fig.~\ref{fig:proc_prog_start_stop}); torneremo su questo aspetto in -cap.~\ref{cha:signals}. +fig.~\ref{fig:proc_prog_start_stop}); tratteremo nei dettagli i segnali e la +loro gestione nel capitolo \ref{cha:signals}. @@ -257,15 +258,16 @@ esecuzione, e le varie funzioni utilizzabili per la sua gestione. \subsection{I concetti generali} \label{sec:proc_mem_gen} -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}\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.} +Ci sono vari modi in cui i sistemi operativi 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}\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 + anche per macchine a 32 bit.} Come accennato in cap.~\ref{cha:intro_unix} questo spazio di indirizzi è virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del @@ -273,41 +275,46 @@ computer; in genere detto spazio non indirizzi possibili sono utilizzabili, e quelli usabili non sono necessariamente adiacenti). -Per la gestione da parte del kernel la memoria virtuale viene divisa in pagine -di dimensione fissa (che ad esempio sono di 4kb su macchine a 32 bit e 8kb -sulle alpha, valori strettamente connessi all'hardware di gestione della -memoria),\footnote{con le versioni più recenti del kernel è possibile anche - utilizzare pagine di dimensioni maggiori, per sistemi con grandi - quantitativi di memoria in cui l'uso di pagine troppo piccole comporta una - perdita di prestazioni.} e ciascuna pagina della memoria virtuale è -associata ad un supporto che può essere una pagina di memoria reale o ad un -dispositivo di stoccaggio secondario (in genere lo spazio disco riservato alla -swap, o i file che contengono il codice). - -Lo stesso pezzo di memoria reale (o di spazio disco) può fare da supporto a -diverse pagine di memoria virtuale appartenenti a processi diversi (come -accade in genere per le pagine che contengono il codice delle librerie -condivise). Ad esempio il codice della funzione \func{printf} starà su una -sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria -virtuale di tutti i processi che hanno detta funzione nel loro codice. - -La corrispondenza fra le pagine della \index{memoria~virtuale}memoria virtuale -e quelle della memoria fisica della macchina viene gestita in maniera -trasparente dall'hardware di 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 -\textsl{paginazione}\index{paginazione} (o \textit{paging}), ed è uno dei -compiti principali del kernel. +Per la gestione da parte del kernel la memoria viene divisa in pagine di +dimensione fissa,\footnote{inizialmente questi erano di 4kb sulle macchine a + 32 bit e di 8kb sulle alpha, con le versioni più recenti del kernel è + possibile anche utilizzare pagine di dimensioni maggiori (4Mb), per sistemi + con grandi quantitativi di memoria in cui l'uso di pagine troppo piccole + comporta una perdita di prestazioni.} e ciascuna pagina nello spazio di +indirizzi virtuale è associata ad un supporto che può essere una pagina di +memoria reale o ad un dispositivo di stoccaggio secondario (come lo spazio +disco riservato alla swap, o i file che contengono il codice). Per ciasun +processo il kernel si cura di mantenere un mappa di queste corrispondenze +nella cosiddetta \itindex{page~table}\textit{page table}.\footnote{questa è + una semplificazione brutale, il meccanismo è molto più complesso; una buona + trattazione di come Linux gestisce la memoria virtuale si trova su + \cite{LinVM}.} + +Una stessa pagina di memoria reale può fare da supporto a diverse pagine di +memoria virtuale appartenenti a processi diversi (come accade in genere per le +pagine che contengono il codice delle librerie condivise). Ad esempio il +codice della funzione \func{printf} starà su una sola pagina di memoria reale +che farà da supporto a tutte le pagine di memoria virtuale di tutti i processi +che hanno detta funzione nel loro codice. + +La corrispondenza fra le pagine della \index{memoria~virtuale} memoria +virtuale di un processo e quelle della memoria fisica della macchina viene +gestita in maniera trasparente dal kernel.\footnote{in genere con l'ausilio + dell'hardware di gestione della memoria (la \textit{Memory Management Unit} + del processore), con i kernel della serie 2.6 è comunque diventato possibile + utilizzare Linux anche su architetture che non dispongono di una MMU.} +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 \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}\index{\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 \itindex{page~fault} \textit{page + fault}; la 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 @@ -319,7 +326,9 @@ Normalmente questo 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 della paginazione\index{paginazione} e -mantenere fisse delle pagine in memoria (vedi sez.~\ref{sec:proc_mem_lock}). +mantenere fisse delle pagine in memoria (vedi +sez.~\ref{sec:proc_mem_lock}). Inoltre per certe applicazioni gli algoritmi di +gestione della memoria \subsection{La struttura della memoria di un processo} @@ -331,12 +340,12 @@ 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}\index{\textit{page~fault}} mandando un segnale \const{SIGSEGV} al -processo, che normalmente ne causa la terminazione immediata. +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 \textsl{la memoria - virtuale}\index{\textit{page~fault}} di un processo. Essa viene divisa in + virtuale} \index{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: @@ -374,8 +383,8 @@ seguenti segmenti: puntatori a \val{NULL}).\footnote{si ricordi che questo vale solo per le variabili che vanno nel segmento dati, e non è affatto vero in generale.} - Storicamente questo segmento viene chiamato BSS (da \textit{block started by - symbol}). La sua dimensione è fissa. + Storicamente questa seconda parte del segmento dati viene chiamata BSS (da + \textit{Block Started by Symbol}). La sua dimensione è fissa. \item Lo \textit{heap}. Tecnicamente lo si può considerare l'estensione del segmento dati, a cui di solito è posto giusto di seguito. È qui che avviene @@ -401,7 +410,7 @@ seguenti segmenti: \begin{figure}[htb] \centering - \includegraphics[height=12cm]{img/memory_layout} + \includegraphics[height=11cm]{img/memory_layout} \caption{Disposizione tipica dei segmenti di memoria di un processo.} \label{fig:proc_mem_layout} \end{figure} @@ -417,9 +426,9 @@ caricamento del programma. \subsection{Allocazione della memoria per i programmi C} \label{sec:proc_mem_alloc} -Il C supporta, a livello di linguaggio, soltanto due modalità di allocazione -della memoria: l'\textsl{allocazione statica} e l'\textsl{allocazione - automatica}. +Il C supporta direttamente, come linguaggio di programmazione, soltanto due +modalità di allocazione della memoria: l'\textsl{allocazione statica} e +l'\textsl{allocazione automatica}. L'\textsl{allocazione statica} è quella con cui sono memorizzate le variabili globali e le variabili statiche, cioè le variabili il cui valore deve essere @@ -434,19 +443,21 @@ una funzione e per le sue variabili locali (le cosiddette \textsl{variabili per queste variabili viene allocato nello stack quando viene eseguita la funzione e liberato quando si esce dalla medesima. -Esiste però un terzo tipo di allocazione, l'\textsl{allocazione dinamica della - memoria}, che non è prevista direttamente all'interno del linguaggio C, ma -che è necessaria quando il quantitativo di memoria che serve è determinabile -solo durante il corso dell'esecuzione del programma. +Esiste però un terzo tipo di allocazione, l'\textsl{allocazione dinamica} +della memoria, che non è prevista direttamente all'interno del linguaggio C, +ma che è necessaria quando il quantitativo di memoria che serve è +determinabile solo durante il corso dell'esecuzione del programma. Il C non consente di usare variabili allocate dinamicamente, non è possibile cioè definire in fase di programmazione una variabile le cui dimensioni possano essere modificate durante l'esecuzione del programma. Per questo le librerie del C forniscono una serie opportuna di funzioni per eseguire -l'allocazione dinamica di memoria (in genere nello heap). Le variabili il -cui contenuto è allocato in questo modo non potranno essere usate direttamente -come le altre, ma l'accesso sarà possibile solo in maniera indiretta, -attraverso dei puntatori. +l'allocazione dinamica di memoria (in genere nello heap). + +Le variabili il cui contenuto è allocato in questo modo non potranno essere +usate direttamente come le altre, ma l'accesso sarà possibile solo in maniera +indiretta, attraverso i puntatori alla memoria loro riservata che si sono +ottenuti dalle funzioni di allocazione. \subsection{Le funzioni \func{malloc}, \func{calloc}, \func{realloc} e @@ -501,7 +512,7 @@ quale si effettua l'allocazione. La memoria allocata dinamicamente deve essere esplicitamente rilasciata usando \func{free}\footnote{le glibc provvedono anche una funzione \func{cfree} definita per compatibilità con SunOS, che è deprecata.} una volta che non -sia più necessaria. Questa funzione vuole come parametro un puntatore +sia più necessaria. Questa funzione vuole come argomento un puntatore restituito da una precedente chiamata a una qualunque delle funzioni di allocazione che non sia già stato liberato da un'altra chiamata a \func{free}, in caso contrario il comportamento della funzione è indefinito. @@ -533,7 +544,7 @@ Un errore abbastanza frequente (specie se si ha a che fare con vettori di puntatori) è quello di chiamare \func{free} più di una volta sullo stesso puntatore; per evitare questo problema una soluzione di ripiego è quella di assegnare sempre a \val{NULL} ogni puntatore liberato con \func{free}, dato -che, quando il parametro è un puntatore nullo, \func{free} non esegue nessuna +che, quando l'argomento è un puntatore nullo, \func{free} non esegue nessuna operazione. Le \acr{glibc} hanno un'implementazione delle routine di allocazione che è @@ -544,9 +555,9 @@ uso una versione meno efficiente delle funzioni suddette, che per tollerante nei confronti di piccoli errori come quello di chiamate doppie a \func{free}. In particolare: \begin{itemize} -\item se la variabile è posta a zero gli errori vengono ignorati. +\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}). + (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} @@ -554,7 +565,7 @@ tollerante nei confronti di piccoli errori come quello di chiamate doppie a Il problema più comune e più difficile da risolvere che si incontra con le routine di allocazione è quando non viene opportunamente liberata la memoria non più utilizzata, quello che in inglese viene chiamato \textit{memory - leak}\index{\textit{memory~leak}}, cioè una \textsl{perdita di memoria}. + leak}\itindex{memory~leak}, cioè una \textsl{perdita di memoria}. 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 @@ -567,56 +578,56 @@ Il problema 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}\index{\textit{memory~leak}}. +\textit{memory leak}\itindex{memory~leak}. In C e C++ il problema è particolarmente sentito. In C++, per mezzo della -programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente -ridimensionato attraverso l'uso accurato di appositi oggetti come gli -\textit{smartpointers}. Questo però va a scapito delle prestazioni -dell'applicazione in esecuzione. - -In altri linguaggi come il java e recentemente il C\# il problema non si pone -nemmeno perché la gestione della memoria viene fatta totalmente in maniera -automatica, ovvero il programmatore non deve minimamente preoccuparsi di -liberare la memoria allocata precedentemente quando non serve più, poiché il -framework gestisce automaticamente la cosiddetta \textit{garbage collection}. -In tal caso, attraverso meccanismi simili a quelli del \textit{reference - counting}, quando una zona di memoria precedentemente allocata non è più -riferita da nessuna parte del codice in esecuzione, può essere deallocata -automaticamente in qualunque momento dall'infrastruttura. - -Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione -(inoltre le applicazioni sviluppate con tali linguaggi di solito non sono -eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria -la presenza di una infrastruttura per la loro interpretazione e pertanto hanno -di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni -compilate direttamente). Questo comporta però il problema della non -predicibilità del momento in cui viene deallocata la memoria precedentemente -allocata da un oggetto. +programmazione ad oggetti, il problema dei \textit{memory + leak}\itindex{memory~leak} è notevolmente ridimensionato attraverso l'uso +accurato di appositi oggetti come gli \textit{smartpointers}. Questo però in +genere va a scapito delle prestazioni dell'applicazione in esecuzione. + +% In altri linguaggi come il java e recentemente il C\# il problema non si pone +% nemmeno perché la gestione della memoria viene fatta totalmente in maniera +% automatica, ovvero il programmatore non deve minimamente preoccuparsi di +% liberare la memoria allocata precedentemente quando non serve più, poiché +% l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta +% \index{\textit{garbage~collection}}\textit{garbage collection}. In tal caso, +% attraverso meccanismi simili a quelli del \textit{reference counting}, quando +% una zona di memoria precedentemente allocata non è più riferita da nessuna +% parte del codice in esecuzione, può essere deallocata automaticamente in +% qualunque momento dall'infrastruttura. + +% Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione +% (inoltre le applicazioni sviluppate con tali linguaggi di solito non sono +% eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria +% la presenza di una infrastruttura per la loro interpretazione e pertanto hanno +% di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni +% compilate direttamente). Questo comporta però il problema della non +% predicibilità del momento in cui viene deallocata la memoria precedentemente +% allocata da un oggetto. Per limitare l'impatto di questi problemi, e semplificare la ricerca di eventuali errori, l'implementazione delle routine di allocazione 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 +tracciare le allocazioni e le disallocazioni, 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). Esistono varie librerie che forniscono dei sostituti opportuni delle routine di allocazione in grado, senza neanche ricompilare il programma,\footnote{esempi sono \textit{Dmalloc} - \href{http://dmalloc.com/}{http://dmalloc.com/} di Gray Watson ed + \href{http://dmalloc.com/}{\textsf{http://dmalloc.com/}} di Gray Watson ed \textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche molto complesse riguardo l'allocazione della memoria. - -\subsection{La funzione \func{alloca}} -\label{sec:proc_mem_alloca} +\subsection{Le funzioni \func{alloca}, \func{brk} e \func{sbrk}} +\label{sec:proc_mem_sbrk_alloca} Una possibile alternativa all'uso di \func{malloc}, che non soffre dei -problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in -precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria -nello heap usa il segmento di stack della funzione corrente. La sintassi è -identica a quella di \func{malloc}, il suo prototipo è: +problemi di \textit{memory leak}\itindex{memory~leak} descritti in precedenza, +è la funzione \funcd{alloca}, che invece di allocare la memoria nello heap usa +il segmento di 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. @@ -632,7 +643,7 @@ quindi non esiste un analogo della \func{free}) in quanto essa viene rilasciata automaticamente al ritorno della funzione. Come è evidente questa funzione ha molti vantaggi, anzitutto permette di -evitare alla radice i problemi di memory leak\index{\textit{memory~leak}}, +evitare alla radice i problemi di \textit{memory leak}\itindex{memory~leak}, dato che non serve più la deallocazione esplicita; inoltre la deallocazione automatica funziona anche quando si usa \func{longjmp} per uscire da una subroutine con un salto non locale da una funzione (vedi @@ -666,14 +677,12 @@ Questo cui torneremo in sez.~\ref{sec:proc_auto_var}. -\subsection{Le funzioni \func{brk} e \func{sbrk}} -\label{sec:proc_mem_sbrk} - -Queste due funzioni 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 -routine di allocazione della memoria viste in sez.~\ref{sec:proc_mem_malloc}. -La prima funzione è \funcd{brk}, ed il suo prototipo è: +Le due funzioni seguenti 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 routine di allocazione della memoria viste in +sez.~\ref{sec:proc_mem_malloc}. 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. @@ -711,6 +720,9 @@ standard descritte in precedenza, che sono costruite su di esse. % \subsection{La personalizzazione delle funzioni di allocazione} % \label{sec:proc_mem_malloc_custom} +% TODO documentare \func{madvise} +% TODO documentare \func{mincore} +% TODO documentare \func{mprotect} forse da mettere insieme a mmap \subsection{Il controllo della memoria virtuale} \label{sec:proc_mem_lock} @@ -752,42 +764,57 @@ motivi per cui si possono avere di queste necessit crittografia richiedono il blocco di alcune pagine di memoria. \end{itemize} -\index{\textit{memory~locking}|(} +\itindbeg{memory~locking} + Il meccanismo che previene la paginazione\index{paginazione} di parte della memoria virtuale di un processo è chiamato \textit{memory locking} (o \textsl{blocco della memoria}). Il blocco è sempre associato alle pagine della memoria virtuale del processo, e non al segmento reale di RAM su cui essa -viene mantenuta. - -La regola è che se un segmento di RAM fa da supporto ad almeno una pagina -bloccata allora esso viene escluso dal meccanismo della +viene mantenuta. La regola è che se un segmento di RAM fa da supporto ad +almeno una pagina bloccata allora esso viene escluso dal meccanismo della paginazione\index{paginazione}. I blocchi non si accumulano, se si blocca due volte la stessa pagina non è necessario sbloccarla due volte, una pagina o è -bloccata oppure no. +bloccata oppure no. Il \textit{memory lock} persiste fintanto che il processo che detiene la memoria bloccata non la sblocca. Chiaramente la terminazione del processo comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di -tutti i suoi \textit{memory lock}. Infine \textit{memory lock} non sono -ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on - write} (vedi sez.~\ref{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 \textit{memory lock} - del padre.} +tutti i suoi \textit{memory lock}. Infine i \textit{memory lock} non sono +ereditati dai processi figli,\footnote{ma siccome Linux usa il + \itindex{copy~on~write}\textit{copy on write} (vedi + sez.~\ref{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 \textit{memory lock} del padre.} e +vengono automaticamente rimossi se si pone in esecuzione un altro programma +con \func{exec} (vedi sez.~\ref{sec:proc_exec}). Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce la memoria fisica disponibile nel sistema, questo ha un evidente impatto su -tutti gli altri processi, per cui solo un processo con i privilegi di -amministratore (vedremo in sez.~\ref{sec:proc_perms} cosa significa) ha la -capacità di bloccare una pagina. Ogni processo può però sbloccare le pagine -relative alla propria memoria. +tutti gli altri processi, per cui fino al kernel 2.6.9 solo un processo con i +privilegi opportuni (la \itindex{capability}\textit{capability} +\const{CAP\_IPC\_LOCK}, vedi sez.~\ref{sec:proc_capabilities}) aveva la +capacità di bloccare una pagina. Il sistema pone dei limiti all'ammontare di memoria di un processo che può essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo standard POSIX.1 richiede che sia definita in \file{unistd.h} la macro \macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il -\textit{memory locking} e la costante \const{PAGESIZE} in \file{limits.h} per -indicare la dimensione di una pagina in byte. +\textit{memory locking}. Inoltre in alcuni sistemi è definita la costante +\const{PAGE\_SIZE} in \file{limits.h} per indicare la dimensione di una pagina +in byte.\footnote{con Linux questo non avviene e si deve ricorrere alla + funzione \func{getpagesize}, vedi sez.~\ref{sec:sys_memory_res}.} + + +Con il kernel 2.6.9 anche un processo normale può bloccare la propria +memoria\footnote{la funzionalità è stata introdotta per non essere costretti a + dare privilegi eccessivi a programmi di crittografia, che necessitano di + questa funzionalità, ma che devono essere usati da utenti normali.} ma +mentre un processo privilegiato non ha limiti sulla quantità di memoria che +può bloccare, un processo normale è soggetto al limite della risorsa +\const{RLIMIT\_MEMLOCK} (vedi sez.~\ref{sec:sys_resource_limit}). In generale +poi ogni processo può sbloccare le pagine relative alla propria memoria, se +però diversi processi bloccano la stessa pagina questa resterà bloccata +fintanto che ci sarà almeno un processo che la blocca. Le funzioni per bloccare e sbloccare la paginazione\index{paginazione} di singole sezioni di memoria sono \funcd{mlock} e \funcd{munlock}; i loro @@ -810,6 +837,8 @@ prototipi sono: corrispondono allo spazio di indirizzi del processo o si è ecceduto il numero massimo consentito di pagine bloccate. \item[\errcode{EINVAL}] \param{len} non è un valore positivo. + \item[\errcode{EPERM}] con un kernel successivo al 2.6.9 il processo non è + privilegiato e si un limite nullo per \const{RLIMIT\_MEMLOCK}. \end{errlist} e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i privilegi richiesti per l'operazione.} @@ -819,7 +848,9 @@ Le due funzioni permettono rispettivamente di bloccare e sbloccare la paginazione\index{paginazione} per l'intervallo di memoria specificato dagli argomenti, che ne indicano nell'ordine l'indirizzo iniziale e la lunghezza. Tutte le pagine che contengono una parte dell'intervallo bloccato sono -mantenute in RAM per tutta la durata del blocco. +mantenute in RAM per tutta la durata del blocco.\footnote{con altri kernel si + può ottenere un errore di \errcode{EINVAL} se \param{addr} non è un multiplo + della dimensione delle pagine di memoria.} Altre due funzioni, \funcd{mlockall} e \funcd{munlockall}, consentono di bloccare genericamente la paginazione\index{paginazione} per l'intero spazio @@ -833,8 +864,10 @@ di indirizzi di un processo. I prototipi di queste funzioni sono: \funcdecl{int munlockall(void)} Sblocca la paginazione per lo spazio di indirizzi del processo corrente. - \bodydesc{Codici di ritorno ed errori sono gli stessi di \func{mlock} - e \func{munlock}.} + \bodydesc{Codici di ritorno ed errori sono gli stessi di \func{mlock} e + \func{munlock}, con un kernel successivo al 2.6.9 l'uso di + func{munlockall} senza la la \itindex{capability}\textit{capability} +\const{CAP\_IPC\_LOCK} genera un errore di \errcode{EPERM}.} \end{functions} L'argomento \param{flags} di \func{mlockall} permette di controllarne il @@ -857,18 +890,19 @@ esempio limitandosi a tutte le pagine allocate a partire da un certo momento. 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 l'occorrenza di un eventuale \textit{page - fault}\index{\textit{page~fault}} causato dal meccanismo di \textit{copy on - write}\index{\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. + fault}\itindex{page~fault} causato dal meccanismo di \textit{copy on + write}\itindex{copy~on~write}. Infatti se nella sezione critica si va ad +utilizzare memoria che non è ancora stata riportata in RAM si potrebbe avere +un \itindex{page~fault}\textit{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 che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri che esse siano state effettivamente portate in memoria, ci si scrive sopra. \index{memoria~virtuale|)} -\index{\textit{memory~locking}|)} +\itindend{memory~locking} @@ -892,26 +926,26 @@ manipolare ed utilizzare le variabili di ambiente. \subsection{Il formato degli argomenti} \label{sec:proc_par_format} -In genere passaggio degli argomenti al programma viene effettuato dalla shell, -che si incarica di leggere la linea di comando e di effettuarne la scansione -(il cosiddetto \textit{parsing}) per individuare le parole che la compongono, -ciascuna delle quali viene considerata un argomento. Di norma per individuare -le parole viene usato come carattere di separazione lo spazio o il tabulatore, -ma il comportamento è modificabile attraverso l'impostazione della variabile -di ambiente \cmd{IFS}. +In genere il passaggio degli argomenti al programma viene effettuato dalla +shell, che si incarica di leggere la linea di comando e di effettuarne la +scansione (il cosiddetto \textit{parsing}) per individuare le parole che la +compongono, ciascuna delle quali viene considerata un argomento. Di norma per +individuare le parole viene usato come carattere di separazione lo spazio o il +tabulatore, ma il comportamento è modificabile attraverso l'impostazione della +variabile di ambiente \cmd{IFS}. \begin{figure}[htb] \centering - \includegraphics[width=11cm]{img/argv_argc} + \includegraphics[width=13cm]{img/argv_argc} \caption{Esempio dei valori di \param{argv} e \param{argc} generati nella scansione di una riga di comando.} \label{fig:proc_argv_argc} \end{figure} Nella scansione viene costruito il vettore di puntatori \param{argv} inserendo -in successione il puntatore alla stringa costituente l'$n$-simo parametro; la +in successione il puntatore alla stringa costituente l'$n$-simo argomento; la variabile \param{argc} viene inizializzata al numero di argomenti trovati, in -questo modo il primo parametro è sempre il nome del programma; un esempio di +questo modo il primo argomento è sempre il nome del programma; un esempio di questo meccanismo è mostrato in fig.~\ref{fig:proc_argv_argc}. @@ -921,7 +955,7 @@ questo meccanismo 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 \param{argv} che inizia con il carattere \texttt{'-'} e -che non sia un singolo \texttt{'-'} o un \texttt{'--'} viene considerato +che non sia un singolo \texttt{'-'} o un \texttt{'-{}-'} viene considerato un'opzione. In genere le opzioni sono costituite da una lettera singola (preceduta dal carattere \cmd{'-'}) e possono avere o no un parametro associato; un comando tipico può essere quello mostrato in @@ -958,9 +992,9 @@ La modalit 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 +mentre se un'opzione che lo richiede non è seguita da un parametro viene ritornato il carattere \texttt{':'}, infine se viene incontrato il valore -\texttt{'--'} la scansione viene considerata conclusa, anche se vi sono altri +\texttt{'-{}-'} la scansione viene considerata conclusa, anche se vi sono altri elementi di \param{argv} che cominciano con il carattere \texttt{'-'}. \begin{figure}[htb] @@ -1019,12 +1053,12 @@ effettua il riordinamento del vettore \param{argv}. \subsection{Opzioni in formato esteso} \label{sec:proc_opt_extended} -Un'estensione di questo schema è costituito dalle cosiddette -\textit{long-options} espresse nella forma \cmd{--option=parameter}, anche la -gestione di queste ultime è stata standardizzata attraverso l'uso di una +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: da finire). +(NdA: questa parte verrà inserita in seguito). \subsection{Le variabili di ambiente} @@ -1050,7 +1084,7 @@ pi fig.~\ref{fig:proc_envirno_list}. \begin{figure}[htb] \centering - \includegraphics[width=11cm]{img/environ_var} + \includegraphics[width=13cm]{img/environ_var} \caption{Esempio di lista delle variabili di ambiente.} \label{fig:proc_envirno_list} \end{figure} @@ -1074,7 +1108,7 @@ delle relative chiamate (si veda sez.~\ref{sec:proc_exec}). La shell ad esempio ne usa molte per il suo funzionamento (come \texttt{PATH} per la ricerca dei comandi, o \texttt{IFS} per la scansione degli argomenti), -e alcune di esse (come \texttt{HOME}, \texttt{USER}, etc.) sono definite al +e alcune di esse (come \texttt{HOME}, \texttt{USER}, ecc.) sono definite al login (per i dettagli si veda sez.~\ref{sec:sess_login}). In genere è cura dell'amministratore definire le opportune variabili di ambiente in uno script di avvio. Alcune servono poi come riferimento generico per molti programmi @@ -1084,7 +1118,7 @@ necessit Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più comuni), come riportato in tab.~\ref{tab:proc_env_var}. GNU/Linux le supporta tutte e ne definisce anche altre: per una lista più completa si può -controllare \cmd{man environ}. +controllare \cmd{man 5 environ}. \begin{table}[htb] \centering @@ -1199,7 +1233,7 @@ separatamente nome e valore della variabile di ambiente, inoltre il valore di variabile esista già, sovrascrivendola se diverso da zero, lasciandola immutata se uguale a zero. -La seconda funzione prende come parametro una stringa analoga quella +La seconda funzione prende come argomento una stringa analoga a quella restituita da \func{getenv}, e sempre nella forma \code{NOME=valore}. Se la variabile specificata non esiste la stringa sarà aggiunta all'ambiente, se invece esiste il suo valore sarà impostato a quello specificato da @@ -1273,7 +1307,7 @@ che viene passato alla subroutine variabile, copia che la subroutine potrà modificare a piacere, senza che il valore originale nella routine chiamante venga toccato. In questo modo non occorre preoccuparsi di eventuali effetti delle operazioni della subroutine -sulla variabile passata come parametro. +sulla variabile passata come argomento. Questo però va inteso nella maniera corretta. Il passaggio \textit{by value} vale per qualunque variabile, puntatori compresi; quando però in una @@ -1292,13 +1326,12 @@ nella programmazione normale. Talvolta però è necessario che la funzione possa restituire indietro alla funzione chiamante un valore relativo ad uno dei suoi argomenti. Per far -questo si usa il cosiddetto -\index{\textit{value~result~argument}}\textit{value result argument}, si passa -cioè, invece di una normale variabile, un puntatore alla stessa; vedremo -alcuni esempi di questa modalità nelle funzioni che gestiscono i socket (in -sez.~\ref{sec:TCP_functions}), in cui, per permettere al kernel di restituire -informazioni sulle dimensioni delle strutture degli indirizzi utilizzate, -viene usato questo meccanismo. +questo si usa il cosiddetto \itindex{value~result~argument}\textit{value + result argument}, si passa cioè, invece di una normale variabile, un +puntatore alla stessa; vedremo alcuni esempi di questa modalità nelle funzioni +che gestiscono i socket (in sez.~\ref{sec:TCP_functions}), in cui, per +permettere al kernel di restituire informazioni sulle dimensioni delle +strutture degli indirizzi utilizzate, viene usato questo meccanismo. \subsection{Il passaggio di un numero variabile di argomenti} @@ -1308,21 +1341,23 @@ Come vedremo nei capitoli successivi, non sempre numero fisso di argomenti per una funzione. Lo standard ISO C prevede nella sua sintassi la possibilità di definire delle \textit{variadic function}\index{variadic} che abbiano un numero variabile di argomenti, -attraverso l'uso della \textit{ellipsis} \code{...} nella dichiarazione della -funzione; ma non provvede a livello di linguaggio alcun meccanismo con cui -dette funzioni possono accedere ai loro argomenti. - -L'accesso viene invece realizzato dalle librerie standard che provvedono gli -strumenti adeguati. L'uso delle \textit{variadic function} prevede tre punti: -\begin{itemize*} +attraverso l'uso nella dichiarazione della funzione dello speciale costrutto +``\texttt{\textellipsis}'', che viene chiamato \textit{ellipsis}. + +Lo standard però non provvede a livello di linguaggio alcun meccanismo con cui +dette funzioni possono accedere ai loro argomenti. L'accesso viene pertanto +realizzato a livello delle librerie standard del C che provvedono gli +strumenti adeguati. L'uso di una \textit{variadic function} prevede quindi +tre punti: +\begin{itemize} \item \textsl{Dichiarare} la funzione come \textit{variadic} usando un prototipo che contenga una \textit{ellipsis}. -\item \textsl{Definire} la funzione come \textit{variadic} usando lo stesso +\item \textsl{Definire} la funzione come \textit{variadic} usando la stessa \textit{ellipsis}, ed utilizzare le apposite macro che consentono la gestione di un numero variabile di argomenti. -\item \textsl{Chiamare} la funzione specificando prima gli argomenti fissi, e - a seguire gli addizionali. -\end{itemize*} +\item \textsl{Invocare} la funzione specificando prima gli argomenti fissi, ed + a seguire quelli addizionali. +\end{itemize} Lo standard ISO C prevede che una \textit{variadic function}\index{variadic} abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione @@ -1332,8 +1367,8 @@ sez.~\ref{sec:proc_exec}: \includecodesnip{listati/exec_sample.c} in questo caso la funzione prende due argomenti fissi ed un numero variabile di altri argomenti (che verranno a costituire gli elementi successivi al primo -del vettore \param{argv} passato al nuovo processo). Lo standard ISO C richiede -inoltre che l'ultimo degli argomenti fissi sia di tipo +del vettore \param{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 \ctyp{float} vengono convertiti @@ -1341,7 +1376,7 @@ inoltre che l'ultimo degli argomenti fissi sia di tipo \ctyp{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso a sé stesso.} il che esclude vettori, 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 +alcuni compilatori è di non dichiarare l'ultimo argomento fisso come \direct{register}. Una volta dichiarata la funzione il secondo passo è accedere ai vari argomenti @@ -1352,7 +1387,7 @@ L'unica modalit sequenziale; essi verranno estratti dallo stack secondo l'ordine in cui sono stati scritti. Per fare questo in \file{stdarg.h} sono definite delle apposite macro; la procedura da seguire è la seguente: -\begin{enumerate*} +\begin{enumerate} \item Inizializzare un puntatore alla lista degli argomenti di tipo \macro{va\_list} attraverso la macro \macro{va\_start}. \item Accedere ai vari argomenti opzionali con chiamate successive alla macro @@ -1360,8 +1395,8 @@ macro; la procedura da seguire il secondo e così via. \item Dichiarare la conclusione dell'estrazione degli argomenti invocando la macro \macro{va\_end}. -\end{enumerate*} -in generale è perfettamente legittimo richiedere meno argomenti di quelli che +\end{enumerate} +In generale è perfettamente legittimo richiedere meno argomenti di quelli che 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 @@ -1378,7 +1413,7 @@ Le definizioni delle tre macro sono le seguenti: l'ultimo degli argomenti fissi. \funcdecl{type va\_arg(va\_list ap, type)} Restituisce il valore del - successivo parametro opzionale, modificando opportunamente \param{ap}; la + successivo argomento opzionale, modificando opportunamente \param{ap}; la macro richiede che si specifichi il tipo dell'argomento attraverso il parametro \param{type} che deve essere il nome del tipo dell'argomento in questione. Il tipo deve essere \textit{self-promoting}. @@ -1393,7 +1428,7 @@ e ciascuno potr Dopo l'uso di \macro{va\_end} la variabile \param{ap} diventa indefinita e successive chiamate a \macro{va\_arg} non funzioneranno. Si avranno risultati indefiniti anche chiamando \macro{va\_arg} specificando un tipo che non -corrisponde a quello del parametro. +corrisponde a quello dell'argomento. Un altro limite delle macro è che i passi 1) e 3) devono essere eseguiti nel corpo principale della funzione, il passo 2) invece può essere eseguito anche @@ -1445,7 +1480,7 @@ stabilire quanti sono gli argomenti passati effettivamente in una chiamata. Esistono varie modalità per affrontare questo problema; una delle più immediate è quella di specificare il numero degli argomenti opzionali come uno -degli argomenti fissi. Una variazione di questo metodo è l'uso di un parametro +degli argomenti fissi. Una variazione di questo metodo è l'uso di un argomento per specificare anche il tipo degli argomenti (come fa la stringa di formato per \func{printf}). @@ -1486,15 +1521,15 @@ programma: quello dell'uscita in caso di errore. \index{salto~non-locale|(} -Il C però non consente di effettuare un salto ad -una etichetta definita in 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 \cite{glibc}, è quello -di un programma nel cui corpo principale vengono letti dei dati in ingresso -sui quali viene eseguita, tramite una serie di funzioni di analisi, una -scansione dei contenuti da si ottengono le indicazioni per l'esecuzione delle -opportune operazioni. +Il C però non consente di effettuare un salto ad una etichetta definita in +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 in \cite{APUE} che in \cite{glibc}, è quello di un programma nel +cui corpo principale vengono letti dei dati in ingresso sui quali viene +eseguita, tramite una serie di funzioni di analisi, una scansione dei +contenuti, da cui si ottengono 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 nei dati in ingresso può accadere @@ -1575,18 +1610,18 @@ pertanto non si pu 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}). + 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. + iterazione; \item come operando per l'operatore di negazione (\code{!}) in una espressione - di controllo di un comando condizionale, di selezione o di iterazione. + 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}. +ottenuta da un \func{longjmp} è costituita dal 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