+%% process.tex
+%%
+%% Copyright (C) 2000-2002 Simone Piccardi. Permission is granted to
+%% copy, distribute and/or modify this document under the terms of the GNU Free
+%% Documentation License, Version 1.1 or any later version published by the
+%% Free Software Foundation; with the Invariant Sections being "Prefazione",
+%% with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
\chapter{L'interfaccia base con i processi}
\label{cha:process_interface}
\end{lstlisting}
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
+\func{main}, che prevede la presenza di un terzo parametro, \code{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
se si vogliono scrivere programmi portabili è meglio evitarla.
incorrere nel caso in cui restituendo un codice di errore 256, si otterrebbe
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
+In \file{stdlib.h} sono definite, seguendo lo standard POSIX, le due costanti
+\const{EXIT\_SUCCESS} e \const{EXIT\_FAILURE}, da usare sempre per specificare
lo stato di uscita di un processo. In Linux esse sono poste rispettivamente ai
valori di tipo \ctyp{int} 0 e 1.
\label{sec:proc_exit}
Come accennato le funzioni usate per effettuare un'uscita ``normale'' da un
-programma sono due, la prima è la funzione \func{exit} che è definita dallo
+programma sono due, la prima è la funzione \funcd{exit}, che è definita dallo
standard ANSI C ed il cui prototipo è:
\begin{prototype}{stdlib.h}{void exit(int status)}
- Causa la conclusione ordinaria del programma restituendo il valore
- \var{status} al processo padre.
+ Causa la conclusione ordinaria del programma.
\bodydesc{La funzione non ritorna. Il processo viene terminato.}
\end{prototype}
\secref{sec:proc_atexit}), e chiude tutti gli stream effettuando il
salvataggio dei dati sospesi (chiamando \func{fclose}, vedi
\secref{sec:file_fopen}), infine passa il controllo al kernel chiamando
-\func{\_exit} e passando \param{status} come stato di uscita.
+\func{\_exit} e restituendo il valore di \param{status} come stato di uscita.
-La system call \func{\_exit} restituisce direttamente il controllo al kernel,
+La system call \funcd{\_exit} restituisce direttamente il controllo al kernel,
concludendo immediatamente il processo; i dati sospesi nei buffer degli stream
non vengono salvati e le eventuali funzioni registrate con \func{atexit} e
\func{on\_exit} non vengono eseguite. Il prototipo della funzione è:
\begin{prototype}{unistd.h}{void \_exit(int status)}
- Causa la conclusione immediata del programma restituendo \param{status} al
- processo padre come stato di uscita.
+ Causa la conclusione immediata del programma.
\bodydesc{La funzione non ritorna. Il processo viene terminato.}
\end{prototype}
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
-\secref{cha:process_handling}), manda un segnale \macro{SIGCHLD} al processo
+\secref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
padre (vedi \secref{sec:sig_job_control}) ed infine ritorna lo stato di uscita
specificato in \param{status} che può essere raccolto usando la funzione
\func{wait} (vedi \secref{sec:proc_wait}).
scopo lo standard ANSI C prevede la possibilità di registrare un certo numero
funzioni che verranno eseguite all'uscita dal programma (sia per la chiamata
ad \func{exit} che per il ritorno di \func{main}). La prima funzione che si
-può utilizzare a tal fine è:
+può utilizzare a tal fine è \funcd{atexit} il cui prototipo è:
\begin{prototype}{stdlib.h}{void atexit(void (*function)(void))}
- Registra la funzione \param{function} per essere chiamata all'uscita dal
- programma.
+ Registra la funzione \param{function} per la chiamata all'uscita dal
+ programma.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
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
-non deve ritornare niente (deve essere essere cioè definita come \code{void
- function(void)}).
+\noindent la funzione richiede come argomento l'indirizzo di una opportuna
+funzione di pulizia da chiamare all'uscita del programma, che non deve
+prendere argomenti e non deve ritornare niente (deve essere essere cioè
+definita come \code{void function(void)}).
-Un'estensione di \func{atexit} è la funzione \func{on\_exit}, che le
+Un'estensione di \func{atexit} è la funzione \funcd{on\_exit}, che le
\acr{glibc} includono per compatibilità con SunOS, ma che non è detto sia
definita su altri sistemi; il suo prototipo è:
\begin{prototype}{stdlib.h}
-{void on\_exit(void (*function)(int status, void *arg), void *arg)}
- Registra la funzione \param{function} per essere chiamata all'uscita dal
- programma. Tutte le funzioni registrate vengono chiamate in ordine inverso
- rispetto a quello di registrazione.
+{void on\_exit(void (*function)(int , void *), void *arg)}
+ Registra la funzione \param{function} per la chiamata all'uscita dal
+ programma.
\bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
fallimento, \var{errno} non viene modificata.}
\end{prototype}
-In questo caso la funzione da chiamare prende due parametri, il primo dei
-quali sarà inizializzato allo stato di uscita con cui è stata chiamata
-\func{exit} ed il secondo al puntatore generico specificato come secondo
-argomento nella chiamata di \func{on\_exit}. Così diventa possibile passare
-dei dati alla funzione di chiusura.
+In questo caso la funzione da chiamare all'uscita prende i due parametri
+specificati nel prototipo, dovrà cioè essere definita come \code{void
+ function(int status, void *argp)}. Il primo argomento sarà inizializzato
+allo stato di uscita con cui è stata chiamata \func{exit} ed il secondo al
+puntatore \param{arg} passato come secondo argomento di \func{on\_exit}. Così
+diventa possibile passare dei dati alla funzione di chiusura.
Nella sequenza di chiusura tutte le funzioni registrate verranno chiamate in
ordine inverso rispetto a quello di registrazione (ed una stessa funzione
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
+ 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 è
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 della paginazione e mantenere fisse delle
-pagine in memoria (vedi \ref{sec:proc_mem_lock}).
+permettono di bloccare il meccanismo della paginazione\index{paginazione} e
+mantenere fisse delle pagine in memoria (vedi \ref{sec:proc_mem_lock}).
\subsection{La struttura della memoria di un processo}
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{page fault}
-mandando un segnale \macro{SIGSEGV} al processo, che normalmente ne causa la
+mandando un segnale \const{SIGSEGV} al processo, che normalmente ne causa la
terminazione immediata.
È pertanto importante capire come viene strutturata \textsl{la memoria
\end{lstlisting}
questo vettore sarà immagazzinato in questo segmento. Anch'esso viene
allocato all'avvio, e tutte le variabili vengono inizializzate a zero (ed i
- puntatori a \macro{NULL}).\footnote{si ricordi che questo vale solo per le
+ 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 BBS (da \textit{block started by
\label{sec:proc_mem_malloc}
Le funzioni previste dallo standard ANSI C per la gestione della memoria sono
-quattro: \func{malloc}, \func{calloc}, \func{realloc} e \func{free}, i loro
-prototipi sono i seguenti:
+quattro: \funcd{malloc}, \funcd{calloc}, \funcd{realloc} e \funcd{free}, i
+loro prototipi sono i seguenti:
\begin{functions}
\headdecl{stdlib.h}
\funcdecl{void *calloc(size\_t size)}
- Alloca \var{size} byte nello heap. La memoria viene inizializzata a 0.
+ Alloca \param{size} byte nello heap. La memoria viene inizializzata a 0.
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} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *malloc(size\_t size)}
- Alloca \var{size} byte nello heap. La memoria non viene inizializzata.
+ Alloca \param{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} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *realloc(void *ptr, size\_t size)}
- Cambia la dimensione del blocco allocato all'indirizzo \var{ptr}
- portandola a \var{size}.
+ Cambia la dimensione del blocco allocato all'indirizzo \param{ptr}
+ portandola a \param{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} assumerà il valore \macro{ENOMEM}.
+ di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void free(void *ptr)}
- Disalloca lo spazio di memoria puntato da \var{ptr}.
+ Disalloca lo spazio di memoria puntato da \param{ptr}.
La funzione non ritorna nulla e non riporta errori.
\end{functions}
32 bit in genere è allineato a multipli di 4 byte e sulle macchine a 64 bit a
multipli di 8 byte.
-In genere su usano le funzioni \func{malloc} e \func{calloc} per allocare
-dinamicamente la memoria necessaria al programma, e siccome i puntatori
-ritornati sono di tipo generico non è necessario effettuare un cast per
-assegnarli a puntatori al tipo di variabile per la quale si effettua
-l'allocazione.
+In genere si usano le funzioni \func{malloc} e \func{calloc} per allocare
+dinamicamente la quantità di memoria necessaria al programma indicata da
+\param{size},\footnote{queste funzioni presentano un comportamento diverso fra
+ le \acr{glibc} e le \acr{uClib} quando il valore di \param{size} è nullo.
+ Nel primo caso viene comunque restituito un puntatore valido, anche se non è
+ chiaro a cosa esso possa fare riferimento, nel secondo caso viene restituito
+ \val{NULL}. Il comportamento è analogo con \code{realloc(NULL, 0)}.} e
+siccome i puntatori ritornati sono di tipo generico non è necessario
+effettuare un cast per assegnarli a puntatori al tipo di variabile per la
+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}
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
+\func{malloc} (se è passato un valore \val{NULL} allora la funzione si
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
Si deve sempre avere ben presente il fatto che il blocco di memoria restituito
da \func{realloc} può non essere un'estensione di quello che gli si è passato
in ingresso; per questo si dovrà \emph{sempre} eseguire la riassegnazione di
-\var{ptr} al valore di ritorno della funzione, e reinizializzare o provvedere
+\param{ptr} al valore di ritorno della funzione, e reinizializzare o provvedere
ad un adeguato aggiornamento di tutti gli altri puntatori all'interno del
blocco di dati ridimensionato.
Un errore abbastanza frequente (specie se si ha a che fare con array 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 \macro{NULL} ogni puntatore liberato con \func{free}, dato
+assegnare sempre a \val{NULL} ogni puntatore liberato con \func{free}, dato
che, quando il parametro è un puntatore nullo, \func{free} non esegue nessuna
operazione.
Le \acr{glibc} hanno un'implementazione delle routine di allocazione che è
controllabile dall'utente attraverso alcune variabili di ambiente, in
particolare diventa possibile tracciare questo tipo di errori usando la
-variabile \macro{MALLOC\_CHECK\_} che quando viene definita mette in uso una
-versione meno efficiente delle funzioni suddette, che però è più tollerante
-nei confronti di piccoli errori come quello di chiamate doppie a \func{free}.
-In particolare:
-\begin{itemize*}
+variabile d'ambiente \val{MALLOC\_CHECK\_} che quando viene definita mette in
+uso una versione meno efficiente delle funzioni suddette, che però è più
+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 è posta ad 1 viene stampato un avviso sullo \textit{standard error}
(vedi \secref{sec:file_std_stream}).
\item se è posta a 2 viene chiamata \func{abort}, che in genere causa
l'immediata conclusione del programma.
-\end{itemize*}
+\end{itemize}
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},
-cioè \textsl{perdita di memoria}.
+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
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à 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).
+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 performance
+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 performance 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 performance 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
+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
+ \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}
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
-problemi di memory leak descritti in precedenza, è la funzione \func{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} 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 \var{size} byte nel segmento di stack della funzione chiamante.
- 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} assumerà il valore \macro{ENOMEM}.
+ Alloca \param{size} byte nello stack.
+
+ \bodydesc{La funzione restituisce il puntatore alla zona di memoria allocata
+ in caso di successo e \val{NULL} in caso di fallimento, nel qual caso
+ \var{errno} assumerà il valore \errval{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
-automaticamente al ritorno della funzione.
+
+La funzione alloca la quantità di memoria (non inizializzata) richiesta
+dall'argomento \param{size} nel segmento di stack della funzione chiamante.
+Con questa funzione non è più necessario liberare la memoria allocata (e
+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, dato che non serve più la
\subsection{Le funzioni \func{brk} e \func{sbrk}}
\label{sec:proc_mem_sbrk}
-L'uso di queste funzioni è necessario solo quando si voglia accedere alle
-analoghe system call a cui fanno da interfaccia. I loro prototipi sono:
-\begin{functions}
- \headdecl{unistd.h}
- \funcdecl{int brk(void *end\_data\_segment)}
- Sposta la fine del segmento dei dati all'indirizzo specificato da
- \var{end\_data\_segment}.
+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 \secref{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.
- La funzione restituisce 0 in caso di successo e -1 in caso di
- fallimento, nel qual caso \var{errno} assumerà il valore \macro{ENOMEM}.
+ \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+ fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}.}
+\end{prototype}
- \funcdecl{void *sbrk(ptrdiff\_t increment)} Incrementa lo spazio dati di un
- programma di \var{increment}. Un valore zero restituisce l'attuale posizione
- della fine del segmento dati.
+La funzione è un'interfaccia diretta all'ominima system call ed imposta
+l'indirizzo finale del segmento dati di un processo all'indirizzo specificato
+da \param{end\_data\_segment}. Quest'ultimo deve essere un valore ragionevole,
+ed inoltre la dimensione totale del segmento non deve comunque eccedere un
+eventuale limite (si veda \secref{sec:sys_resource_limit}) imposto sulle
+dimensioni massime dello spazio dati del processo.
+
+La seconda funzione per la manipolazione delle dimensioni del segmento
+dati\footnote{in questo caso si tratta soltanto di una funzione di libreria, e
+ non di una sistem call.} è \funcd{sbrk}, ed il suo prototipo è:
+\begin{prototype}{unistd.h}{void *sbrk(ptrdiff\_t increment)}
+ Incrementa la dimensione dello spazio dati.
- 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} 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.
+ \bodydesc{La funzione restituisce il puntatore all'inizio della nuova zona
+ di memoria allocata in caso di successo e \val{NULL} in caso di
+ fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}.}
+\end{prototype}
+\noindent la funzione incrementa la dimensione lo spazio dati di un programma
+di \param{increment} byte, restituendo il nuovo indirizzo finale dello stesso.
+Un valore nullo permette di ottenere l'attuale posizione della fine del
+segmento dati.
Queste funzioni sono state deliberatamente escluse dallo standard POSIX.1 e
per i programmi normali è sempre opportuno usare le funzioni di allocazione
-standard descritte in precedenza, che sono costruite su di esse. L'uso di
-queste funzione è ristretto alle specifiche necessità di chi debba
-implementare una sua versione delle routine di allocazione.
+standard descritte in precedenza, che sono costruite su di esse.
% \subsection{La personalizzazione delle funzioni di allocazione}
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
- riportare la pagina in memoria; per questo motivo processi critici che hanno
- esigenze di tempo reale o tolleranze critiche nelle risposte (ad esempio
- processi che trattano campionamenti sonori) possono non essere in grado di
- sopportare le variazioni della velocità di accesso dovuta alla paginazione.
+\item \textsl{La velocità}. Il processo della paginazione\index{paginazione} è
+ trasparente solo se il programma in esecuzione non è sensibile al tempo che
+ occorre a riportare la pagina in memoria; per questo motivo processi critici
+ che hanno esigenze di tempo reale o tolleranze critiche nelle risposte (ad
+ esempio processi che trattano campionamenti sonori) possono non essere in
+ grado di sopportare le variazioni della velocità di accesso dovuta alla
+ paginazione.
In certi casi poi un programmatore può conoscere meglio dell'algoritmo di
allocazione delle pagine le esigenze specifiche del suo programma e decidere
\item \textsl{La sicurezza}. Se si hanno password o chiavi segrete in chiaro
in memoria queste possono essere portate su disco dal meccanismo della
- paginazione. Questo rende più lungo il periodo di tempo in cui detti segreti
- sono presenti in chiaro e più complessa la loro cancellazione (un processo
- può cancellare la memoria su cui scrive le sue variabili, ma non può toccare
- lo spazio disco su cui una pagina di memoria può essere stata salvata). Per
- questo motivo di solito i programmi di crittografia richiedono il blocco di
- alcune pagine di memoria.
+ paginazione\index{paginazione}. Questo rende più lungo il periodo di tempo
+ in cui detti segreti sono presenti in chiaro e più complessa la loro
+ cancellazione (un processo può cancellare la memoria su cui scrive le sue
+ variabili, ma non può toccare lo spazio disco su cui una pagina di memoria
+ può essere stata salvata). Per questo motivo di solito i programmi di
+ crittografia richiedono il blocco di alcune pagine di memoria.
\end{itemize}
-Il meccanismo che previene la 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.
+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 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 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.
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}.
-
-I \textit{memory lock} non sono ereditati dai processi figli.\footnote{ma
- 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
+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}\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 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 \secref{sec:proc_perms} cosa significa) 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
-standard POSIX.1 richiede che sia definita in \file{unistd.h} la costante
+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 \macro{PAGESIZE} in \file{limits.h} per
+\textit{memory locking} e la costante \const{PAGESIZE} in \file{limits.h} per
indicare la dimensione di una pagina in byte.
-Le funzioni per bloccare e sbloccare singole sezioni di memoria sono
-\func{mlock} e \func{munlock}; i loro prototipi sono:
+Le funzioni per bloccare e sbloccare la paginazione\index{paginazione} di
+singole sezioni di memoria sono \funcd{mlock} e \funcd{munlock}; i loro
+prototipi sono:
\begin{functions}
\headdecl{sys/mman.h}
\funcdecl{int mlock(const void *addr, size\_t len)}
- Blocca la paginazione per l'intervallo di memoria da \var{addr} per
- \var{len} byte. Tutte le pagine che contengono una parte dell'intervallo
- sono mantenute in RAM per tutta la durata del blocco.
+ Blocca la paginazione su un intervallo di memoria.
\funcdecl{int munlock(const void *addr, size\_t len)}
- Sblocca l'intervallo di memoria da \var{addr} per \var{len} byte.
+ Rimuove il blocco della paginazione su un intervallo di memoria.
\bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 in
caso di errore, nel qual caso \var{errno} assumerà uno dei
valori seguenti:
\begin{errlist}
- \item[\macro{ENOMEM}] alcuni indirizzi dell'intervallo specificato non
+ \item[\errcode{ENOMEM}] alcuni indirizzi dell'intervallo specificato non
corrispondono allo spazio di indirizzi del processo o si è ecceduto
il numero massimo consentito di pagine bloccate.
- \item[\macro{EINVAL}] \var{len} non è un valore positivo.
+ \item[\errcode{EINVAL}] \param{len} non è un valore positivo.
\end{errlist}
- e, per \func{mlock}, anche \macro{EPERM} quando il processo non ha i
+ e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i
privilegi richiesti per l'operazione.}
\end{functions}
-Altre due funzioni, \func{mlockall} e \func{munlockall}, consentono di
-bloccare genericamente lo spazio di indirizzi di un processo. I prototipi di
-queste funzioni sono:
+Le due funzioni permettono rispettivamente di bloccare e sbloccare la
+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 sono mantenute in RAM per tutta la durata
+del blocco.
+Altre due funzioni, \funcd{mlockall} e \funcd{munlockall}, consentono poi di
+bloccare genericamente la paginazione\index{paginazione} per l'intero spazio
+di indirizzi di un processo. I prototipi di queste funzioni sono:
\begin{functions}
\headdecl{sys/mman.h}
e \func{munlock}.}
\end{functions}
-Il parametro \var{flags} di \func{mlockall} permette di controllarne il
+L'argomento \param{flags} di \func{mlockall} permette di controllarne il
comportamento; esso può essere specificato come l'OR aritmetico delle due
costanti:
\begin{basedescript}{\desclabelwidth{2.5cm}}
-\item[\macro{MCL\_CURRENT}] blocca tutte le pagine correntemente mappate nello
+\item[\const{MCL\_CURRENT}] blocca tutte le pagine correntemente mappate nello
spazio di indirizzi del processo.
-\item[\macro{MCL\_FUTURE}] blocca tutte le pagine che saranno mappate nello
+\item[\const{MCL\_FUTURE}] blocca tutte le pagine che saranno mappate nello
spazio di indirizzi del processo.
\end{basedescript}
Tutti i programmi hanno la possibilità di ricevere parametri e opzioni quando
vengono lanciati. Il passaggio dei parametri è effettuato attraverso gli
-argomenti \var{argc} e \var{argv} della funzione \func{main}, che vengono
+argomenti \param{argc} e \param{argv} della funzione \func{main}, che vengono
passati al programma dalla shell (o dal processo che esegue la \func{exec},
secondo le modalità che vedremo in \secref{sec:proc_exec}) quando questo viene
messo in esecuzione.
\begin{figure}[htb]
\centering
\includegraphics[width=11cm]{img/argv_argc}
- \caption{Esempio dei valori di \var{argv} e \var{argc} generati nella
+ \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 \var{argv} inserendo
+Nella scansione viene costruito il vettore di puntatori \param{argv} inserendo
in successione il puntatore alla stringa costituente l'$n$-simo parametro; la
-variabile \var{argc} viene inizializzata al numero di parametri trovati, in
+variabile \param{argc} viene inizializzata al numero di parametri trovati, in
questo modo il primo parametro è sempre il nome del programma; un esempio di
questo meccanismo è mostrato in \figref{fig:proc_argv_argc}.
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 il carattere \texttt{'-'} e che
-non sia un singolo \texttt{'-'} o un \texttt{'--'} viene considerato
+tali: un elemento di \param{argv} che inizia con il carattere \texttt{'-'} e
+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
argomento del programma, non un parametro di \cmd{-m}).
Per gestire le opzioni all'interno dei argomenti a linea di comando passati in
-\var{argv} le librerie standard del C forniscono la funzione \func{getopt}
+\param{argv} le librerie standard del C forniscono la funzione \funcd{getopt},
che ha il seguente prototipo:
\begin{prototype}{unistd.h}
{int getopt(int argc, char *const argv[], const char *optstring)}
Esegue il parsing degli argomenti passati da linea di comando
-riconoscendo le possibili opzioni segnalate con \var{optstring}.
+riconoscendo le possibili opzioni segnalate con \param{optstring}.
\bodydesc{Ritorna il carattere che segue l'opzione, \cmd{':'} se manca un
parametro all'opzione, \cmd{'?'} se l'opzione è sconosciuta, e -1 se non
esistono altre opzioni.}
\end{prototype}
-Questa funzione prende come argomenti le due variabili \var{argc} e \var{argv}
-passate a \func{main} ed una stringa che indica quali sono le opzioni valide;
-la funzione effettua la scansione della lista degli argomenti ricercando ogni
-stringa che comincia con \cmd{-} e ritorna ogni volta che trova un'opzione
-valida.
+Questa funzione prende come argomenti le due variabili \param{argc} e
+\param{argv} passate a \func{main} ed una stringa che indica quali sono le
+opzioni valide; la funzione effettua la scansione della lista degli argomenti
+ricercando ogni stringa che comincia con \cmd{-} e ritorna ogni volta che
+trova un'opzione valida.
-La stringa \var{optstring} indica quali sono le opzioni riconosciute ed è
+La stringa \param{optstring} indica quali sono le opzioni riconosciute ed è
costituita da tutti i caratteri usati per identificare le singole opzioni, se
l'opzione ha un parametro al carattere deve essere fatto seguire un segno di
due punti \texttt{':'}; nel caso di \figref{fig:proc_argv_argc} ad esempio la
La modalità di uso di \func{getopt} è pertanto quella di chiamare più volte la
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 \var{optstring} viene ritornato il carattere \texttt{'?'}
+dichiarata in \param{optstring} viene ritornato il carattere \texttt{'?'}
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
-elementi di \var{argv} che cominciano con il carattere \texttt{'-'}.
+elementi di \param{argv} che cominciano con il carattere \texttt{'-'}.
\begin{figure}[htb]
\footnotesize
\item \var{char *optarg} contiene il puntatore alla stringa parametro
dell'opzione.
\item \var{int optind} alla fine della scansione restituisce l'indice del
- primo elemento di \var{argv} che non è un'opzione.
+ primo elemento di \param{argv} che non è un'opzione.
\item \var{int opterr} previene, se posto a zero, la stampa di un messaggio
di errore in caso di riconoscimento di opzioni non definite.
\item \var{int optopt} contiene il carattere dell'opzione non riconosciuta.
(il cui indirizzo è contenuto nella variabile \var{optarg}) avvalorando la
relativa variabile (\texttt{\small 12-14}, \texttt{\small 15-17} e
\texttt{\small 18-20}). Completato il ciclo troveremo in \var{optind} l'indice
-in \var{argv[]} del primo degli argomenti rimanenti nella linea di comando.
-
-Normalmente \func{getopt} compie una permutazione degli elementi di \var{argv}
-cosicché 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 è 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
-attiva quando \var{optstring} inizia con il carattere \texttt{'-'}. In questo
-caso ogni elemento che non è un'opzione viene considerato comunque un'opzione
-e associato ad un valore di ritorno pari ad 1, questo permette di identificare
-gli elementi che non sono opzioni, ma non effettua il riordinamento del
-vettore \var{argv}.
+in \code{argv[]} del primo degli argomenti rimanenti nella linea di comando.
+
+Normalmente \func{getopt} compie una permutazione degli elementi di
+\param{argv} cosicché 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 \param{argv}; se \param{optstring} inizia
+con il carattere \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 attiva quando \param{optstring} inizia con il carattere
+\texttt{'-'}. In questo caso ogni elemento che non è un'opzione viene
+considerato comunque un'opzione e associato ad un valore di ritorno pari ad 1,
+questo permette di identificare gli elementi che non sono opzioni, ma non
+effettua il riordinamento del vettore \param{argv}.
\subsection{Opzioni in formato esteso}
Come per la lista dei parametri anche questa lista è un array di puntatori a
caratteri, ciascuno dei quali punta ad una stringa, terminata da un
-\macro{NULL}. A differenza di \var{argv[]} in questo caso non si ha una
-lunghezza dell'array data da un equivalente di \var{argc}, ma la lista è
+\val{NULL}. A differenza di \code{argv[]} in questo caso non si ha una
+lunghezza dell'array data da un equivalente di \param{argc}, ma la lista è
terminata da un puntatore nullo.
L'indirizzo della lista delle variabili di ambiente è passato attraverso la
\end{figure}
Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo
-\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate
+\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate
in \figref{fig:proc_envirno_list}, sono definite dal sistema per essere usate
da diversi programmi e funzioni: per queste c'è l'ulteriore convenzione di
-usare nomi espressi in caratteri maiuscoli.
+usare nomi espressi in caratteri maiuscoli.\footnote{la convenzione vuole che
+ si usino dei nomi maiuscoli per le variabili di ambiente di uso generico, i
+ nomi minuscoli sono in genere riservati alle variabili interne degli script
+ di shell.}
Il kernel non usa mai queste variabili, il loro uso e la loro interpretazione è
riservata alle applicazioni e ad alcune funzioni di libreria; in genere esse
costituiscono un modo comodo per definire un comportamento specifico senza
dover ricorrere all'uso di opzioni a linea di comando o di file di
-configurazione.
+configurazione. É di norma cura della shell, quando esegue un comando, passare
+queste variabili al programma messo in esecuzione attraverso un uso opportuno
+delle relative chiamate (si veda \secref{sec:proc_exec}).
La shell ad esempio ne usa molte per il suo funzionamento (come \var{PATH} per
la ricerca dei comandi, o \cmd{IFS} per la scansione degli argomenti), e
-alcune di esse (come \var{HOME}, \var{USER}, etc.) sono definite al 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 (come \var{EDITOR} che indica l'editor preferito da invocare in caso
-di necessità).
+alcune di esse (come \var{HOME}, \var{USER}, etc.) sono definite al login (per
+i dettagli si veda \secref{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
+(come \var{EDITOR} che indica l'editor preferito da invocare in caso di
+necessità).
Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più
comuni), come riportato in \tabref{tab:proc_env_var}. GNU/Linux le supporta
\begin{table}[htb]
\centering
+ \footnotesize
\begin{tabular}[c]{|l|c|c|c|p{7cm}|}
\hline
\textbf{Variabile} & \textbf{POSIX} & \textbf{XPG3}
& \textbf{Linux} & \textbf{Descrizione} \\
\hline
\hline
- \macro{USER} & $\bullet$ & $\bullet$ & $\bullet$ & Nome utente\\
- \macro{LOGNAME} & $\bullet$ & $\bullet$ & $\bullet$ & Nome di login\\
- \macro{HOME} & $\bullet$ & $\bullet$ & $\bullet$ &
+ \val{USER} & $\bullet$ & $\bullet$ & $\bullet$ & Nome utente\\
+ \val{LOGNAME} & $\bullet$ & $\bullet$ & $\bullet$ & Nome di login\\
+ \val{HOME} & $\bullet$ & $\bullet$ & $\bullet$ &
Directory base dell'utente\\
- \macro{LANG} & $\bullet$ & $\bullet$ & $\bullet$ & Localizzazione\\
- \macro{PATH} & $\bullet$ & $\bullet$ & $\bullet$ & Elenco delle directory
- dei programmi\\
- \macro{PWD} & $\bullet$ & $\bullet$ & $\bullet$ & Directory corrente\\
- \macro{SHELL} & $\bullet$ & $\bullet$ & $\bullet$ & Shell in uso\\
- \macro{TERM} & $\bullet$ & $\bullet$ & $\bullet$ & Tipo di terminale\\
- \macro{PAGER} & $\bullet$ & $\bullet$ & $\bullet$ & Programma per vedere i
- testi\\
- \macro{EDITOR} & $\bullet$ & $\bullet$ & $\bullet$ & Editor preferito\\
- \macro{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser preferito\\
+ \val{LANG} & $\bullet$ & $\bullet$ & $\bullet$ & Localizzazione\\
+ \val{PATH} & $\bullet$ & $\bullet$ & $\bullet$ & Elenco delle directory
+ dei programmi\\
+ \val{PWD} & $\bullet$ & $\bullet$ & $\bullet$ & Directory corrente\\
+ \val{SHELL} & $\bullet$ & $\bullet$ & $\bullet$ & Shell in uso\\
+ \val{TERM} & $\bullet$ & $\bullet$ & $\bullet$ & Tipo di terminale\\
+ \val{PAGER} & $\bullet$ & $\bullet$ & $\bullet$ & Programma per vedere i
+ testi\\
+ \val{EDITOR} & $\bullet$ & $\bullet$ & $\bullet$ & Editor preferito\\
+ \val{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser preferito\\
+ \val{TMPDIR} & $\bullet$ & $\bullet$ & $\bullet$ & Directory dei file
+ temporanei\\
\hline
\end{tabular}
- \caption{Variabili di ambiente più comuni definite da vari standard.}
+ \caption{Esempi di variabili di ambiente più comuni definite da vari
+ standard.}
\label{tab:proc_env_var}
\end{table}
-Lo standard ANSI C prevede l'esistenza di un ambiente, pur non entrando nelle
-specifiche di come sono strutturati i contenuti, e definisce la funzione
-\func{getenv} che permette di ottenere i valori delle variabili di ambiente,
-il cui prototipo è:
+Lo standard ANSI C prevede l'esistenza di un ambiente, e pur non entrando
+nelle specifiche di come sono strutturati i contenuti, definisce la funzione
+\funcd{getenv} che permette di ottenere i valori delle variabili di ambiente;
+il suo prototipo è:
\begin{prototype}{stdlib.h}{char *getenv(const char *name)}
Esamina l'ambiente del processo cercando una stringa che corrisponda a
quella specificata da \param{name}.
- \bodydesc{La funzione ritorna \macro{NULL} se non trova nulla, o il
+ \bodydesc{La funzione ritorna \val{NULL} se non trova nulla, o il
puntatore alla stringa che corrisponde (di solito nella forma
\cmd{NOME=valore}).}
\end{prototype}
\begin{table}[htb]
\centering
+ \footnotesize
\begin{tabular}[c]{|l|c|c|c|c|c|c|}
\hline
\textbf{Funzione} & \textbf{ANSI C} & \textbf{POSIX.1} & \textbf{XPG3} &
\label{tab:proc_env_func}
\end{table}
-In Linux solo le prime quattro funzioni di \tabref{tab:proc_env_func} sono
-definite, \func{getenv} l'abbiamo già esaminata; delle tre restanti le prime
-due, \func{putenv} e \func{setenv}, servono per assegnare nuove variabili di
-ambiente, i loro prototipi sono i seguenti:
+In Linux sono definite solo le prime quattro delle funzioni elencate in
+\tabref{tab:proc_env_func}. La prima, \func{getenv}, l'abbiamo appena
+esaminata; delle tre restanti le prime due, \funcd{putenv} e \funcd{setenv},
+servono per assegnare nuove variabili di ambiente, i loro prototipi sono i
+seguenti:
\begin{functions}
\headdecl{stdlib.h}
all'ambiente.
\bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 per un
- errore, che è sempre \macro{ENOMEM}.}
+ errore, che è sempre \errval{ENOMEM}.}
\end{functions}
-\noindent la terza, \func{unsetenv}, serve a cancellare una variabile di
+\noindent la terza, \funcd{unsetenv}, serve a cancellare una variabile di
ambiente; il suo prototipo è:
\begin{functions}
\headdecl{stdlib.h}
immutata se uguale a zero.
La seconda funzione prende come parametro una stringa analoga quella
-restituita da \func{getenv}, e sempre nella forma \var{NOME=valore}. Se la
+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
\param{string}. Si tenga presente che, seguendo lo standard SUSv2, le
numero fisso di parametri per una funzione. Lo standard ISO C prevede nella
sua sintassi la possibilità di definire delle \textit{variadic function} che
abbiano un numero variabile di argomenti, attraverso l'uso della
-\textit{ellipsis} \var{...} nella dichiarazione della funzione; ma non
+\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.
\end{lstlisting}
in questo caso la funzione prende due parametri fissi ed un numero variabile
di altri parametri (che verranno a costituire gli elementi successivi al primo
-del vettore \var{argv} passato al nuovo processo). Lo standard ISO C richiede
+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}
macro; la procedura da seguire è la seguente:
\begin{enumerate*}
\item Inizializzare un puntatore alla lista degli argomenti di tipo
- \type{va\_list} attraverso la macro \macro{va\_start}.
+ \macro{va\_list} attraverso la macro \macro{va\_start}.
\item Accedere ai vari argomenti opzionali con chiamate successive alla macro
\macro{va\_arg}, la prima chiamata restituirà il primo argomento, la seconda
il secondo e così via.
ciascuno andrà inizializzato con \macro{va\_start} e letto con \macro{va\_arg}
e ciascuno potrà scandire la lista degli argomenti per conto suo.
-Dopo l'uso di \macro{va\_end} la variabile \var{ap} diventa indefinita e
+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.
in una subroutine passandole il puntatore alla lista di argomenti; in questo
caso però si richiede che al ritorno della funzione il puntatore non venga più
usato (lo standard richiederebbe la chiamata esplicita di \macro{va\_end}),
-dato che il valore di \var{ap} risulterebbe indefinito.
+dato che il valore di \param{ap} risulterebbe indefinito.
Esistono dei casi in cui è necessario eseguire più volte la scansione dei
parametri e poter memorizzare una posizione durante la stessa. La cosa più
Una modalità diversa, che può essere applicata solo quando il tipo dei
parametri lo rende possibile, è quella che prevede di usare un valore speciale
come ultimo argomento (come fa ad esempio \func{execl} che usa un puntatore
-\macro{NULL} per indicare la fine della lista degli argomenti).
+\val{NULL} per indicare la fine della lista degli argomenti).
\subsection{Potenziali problemi con le variabili automatiche}
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 è:
+\funcd{setjmp}, il cui prototipo è:
\begin{functions}
\headdecl{setjmp.h}
\funcdecl{void setjmp(jmp\_buf env)}
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
+stabilito con \func{setjmp} si usa la funzione \funcd{longjmp}; il suo
prototipo è:
\begin{functions}
\headdecl{setjmp.h}
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.
+delle variabili automatiche (o di quelle dichiarate
+\direct{register}\footnote{la direttiva \direct{register} del compilatore
+ chiede che la variabile dichiarata tale sia mantenuta, nei limiti del
+ possibile, all'interno di un registro del processore. Questa direttiva
+ origina dai primi compilatori, quando stava al programmatore scrivere codice
+ ottimizzato, riservando esplicitamente alle variabili più usate l'uso dei
+ registri del processore. Oggi questa direttiva oggi è in disuso dato che
+ tutti i compilatori sono normalmente in grado di valutare con maggior
+ efficacia degli stessi programmatori quando sia il caso di eseguire questa
+ ottimizzazione.}) 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
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}.
+\direct{volatile}\footnote{la direttiva \ctyp{volatile} informa il compilatore
+ che la variabile che è dichiarata può essere modificata, durante
+ l'esecuzione del nostro, da altri programmi. Per questo motivo occorre dire
+ al compilatore che non deve essere mai utilizzata l'ottimizzazione per cui
+ quanto opportuno essa viene mantenuta in un registro, poiché in questo modo
+ si perderebbero le eventuali modifiche fatte dagli altri programmi (che
+ avvengono solo in una copia posta in memoria).}.