X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=3069d292982dddf97840eb29484c09a5d403ca41;hp=e5e4b50ab66464dd828c8eead3a339c6d7a263ee;hb=46029a05c9009df38022e82b0f20732290388ef1;hpb=477c80ba90e4571eb046af49b64dba15eb5a08bf diff --git a/process.tex b/process.tex index e5e4b50..3069d29 100644 --- a/process.tex +++ b/process.tex @@ -1,3 +1,13 @@ +%% 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} @@ -105,8 +115,8 @@ valore dello stato di uscita 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. @@ -146,7 +156,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 -\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}). @@ -222,7 +232,7 @@ volontariamente la sua esecuzione \func{exit} o il ritorno di \func{main}. Uno schema riassuntivo che illustra le modalità con cui si avvia e conclude -normalmente un programma è riportato in \nfig. +normalmente un programma è riportato in \figref{fig:proc_prog_start_stop}. \begin{figure}[htb] \centering @@ -233,7 +243,8 @@ normalmente un programma Si ricordi infine che un programma può anche essere interrotto dall'esterno attraverso l'uso di un segnale (modalità di conclusione non mostrata in -\curfig); torneremo su questo aspetto in \capref{cha:signals}. +\figref{fig:proc_prog_start_stop}); torneremo su questo aspetto in +\capref{cha:signals}. @@ -321,7 +332,7 @@ commette quando si 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 @@ -364,7 +375,7 @@ seguenti segmenti: \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 @@ -455,21 +466,21 @@ prototipi sono i seguenti: Alloca \var{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. 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}. 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}. @@ -480,11 +491,16 @@ allineato correttamente per tutti i tipi di dati; ad esempio sulle macchine a 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} @@ -497,7 +513,7 @@ in caso contrario il comportamento della funzione 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 @@ -520,29 +536,29 @@ 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 @@ -557,29 +573,61 @@ essere in una sezione del codice che non ha alcuna relazione con la subroutine che contiene l'errore. Per questo motivo è sempre molto difficile trovare un \textit{memory leak}. -Per ovviare a questi problemi l'implementazione delle routine di allocazione -delle \acr{glibc} mette a disposizione una serie di funzionalità 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 +\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 è: \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}. + 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 @@ -631,15 +679,15 @@ analoghe system call a cui fanno da interfaccia. I loro prototipi sono: \var{end\_data\_segment}. La funzione restituisce 0 in caso di successo e -1 in caso di - fallimento, nel qual caso \var{errno} assumerà il valore \macro{ENOMEM}. + fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}. \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 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}. + allocata in caso di successo e \val{NULL} in caso di fallimento, nel qual + caso \var{errno} assumerà il valore \errval{ENOMEM}. \end{functions} \noindent in genere si usa \func{sbrk} con un valore zero per ottenere l'attuale posizione della fine del segmento dati. @@ -647,7 +695,7 @@ 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 +queste funzioni è ristretto alle specifiche necessità di chi debba implementare una sua versione delle routine di allocazione. @@ -706,23 +754,25 @@ sbloccarla due volte, una pagina o 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 @@ -743,12 +793,12 @@ Le funzioni per bloccare e sbloccare singole sezioni di memoria sono 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}] \var{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} @@ -773,9 +823,9 @@ Il parametro \var{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} @@ -842,7 +892,7 @@ Nella scansione viene costruito il vettore di puntatori \var{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 questo modo il primo parametro è sempre il nome del programma; un esempio di -questo meccanismo è mostrato in \curfig. +questo meccanismo è mostrato in \figref{fig:proc_argv_argc}. \subsection{La gestione delle opzioni} @@ -961,7 +1011,7 @@ 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}) +\texttt{'+'} (o è impostata la variabile di ambiente \val{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 @@ -993,7 +1043,7 @@ nella chiamata alla funzione \func{exec} quando questo viene lanciato. 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 +\val{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 è terminata da un puntatore nullo. @@ -1014,66 +1064,77 @@ pi \end{figure} Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo -\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate -in \curfig, 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. +\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.\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 \ntab. GNU/Linux le supporta tutte e ne definisce -anche altre: per una lista più completa si può controllare \cmd{man environ}. +comuni), come riportato in \tabref{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}. \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 +\func{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} @@ -1082,10 +1143,11 @@ Oltre a questa funzione di lettura, che C, nell'evoluzione dei sistemi Unix ne sono state proposte altre, da utilizzare per impostare e per cancellare le variabili di ambiente. Uno schema delle funzioni previste nei vari standard e disponibili in Linux è riportato -in \ntab. +in \tabref{tab:proc_env_func}. \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} & @@ -1108,10 +1170,11 @@ in \ntab. \label{tab:proc_env_func} \end{table} -In Linux solo le prime quattro funzioni di \curtab\ 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, \func{putenv} e \func{setenv}, +servono per assegnare nuove variabili di ambiente, i loro prototipi sono i +seguenti: \begin{functions} \headdecl{stdlib.h} @@ -1122,7 +1185,7 @@ ambiente, i loro prototipi sono i seguenti: 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 ambiente; il suo prototipo è: @@ -1281,7 +1344,7 @@ stati scritti. Per fare questo in \file{stdarg.h} sono definite delle apposite 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. @@ -1378,7 +1441,7 @@ per \func{printf}). 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} @@ -1506,8 +1569,16 @@ Uno dei punti critici dei salti non-locali 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 @@ -1516,7 +1587,13 @@ chiamata ad un'altra funzioni vengono salvati nel contesto nello stack) torneranno al valore avuto al momento della chiamata di \func{setjmp}; per questo quando si vuole avere un comportamento coerente si può bloccare l'ottimizzazione che porta le variabili nei registri dichiarandole tutte come -\code{volatile}. +\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).}.