discorso dei \textit{thread} comunque in Linux necessita di una trattazione a
parte per la peculiarità dell'implementazione).
+
\subsection{La funzione \func{main}}
\label{sec:proc_main}
La funzione non ritorna. Il processo viene terminato.
\end{prototype}
-La funzione chiude tutti i file descriptor appartenenti al processo (sui tenga
+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 si che ogni figlio del processo sia ereditato da \cmd{init}
(vedi \secref{cha:process_handling}), manda un segnale \macro{SIGCHLD} al
\begin{figure}[htb]
\centering
-
+ \includegraphics[width=12cm]{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
\curfig); torneremo su questo aspetto in \secref{cha:signals}.
\begin{figure}[htb]
\centering
- \includegraphics[width=5cm]{img/memory_layout.eps}
+ \includegraphics[width=5cm]{img/memory_layout}
\caption{Disposizione tipica dei segmenti di memoria di un processo}
\label{fig:proc_mem_layout}
\end{figure}
\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_stdfiles}).
+ (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*}
di successo e \macro{NULL} in caso di fallimento, nel qual caso
\var{errno} viene settata a \macro{ENOMEM}.
\end{prototype}
-ma in questo caso non è più necessario liberare la memoria in quanto questa
-viene rilasciata automaticamente al ritorno della funzione.
+\noindent ma in questo caso non è più necessario liberare la memoria in quanto
+questa viene rilasciata automaticamente al ritorno della funzione.
Come è evidente questa funzione ha molti vantaggi, e permette di evitare i
problemi di memory leak non essendo più necessaria la deallocazione esplicita;
una delle ragioni principali per usarla è però che funziona anche quando si
-usa \func{longjump} per uscire con un salto non locale da una funzione (vedi
+usa \func{longjmp} per uscire con un salto non locale da una funzione (vedi
\secref{sec:proc_longjmp}),
Un altro vantaggio e che in Linux la funzione è molto veloce e non viene
caso \var{errno} è settata ad uno dei valori seguenti:
\begin{errlist}
\item \macro{ENOMEM} alcuni indirizzi dell'intervallo specificato non
- corripondono allo spazio di indirizzi del processo o si è ecceduto il
+ corrispondono allo spazio di indirizzi del processo o si è ecceduto il
numero massimo consentito di pagine bloccate.
\item \macro{EPERM} il processo non ha i privilegi richiesti per
l'operazione.
\var{errno} è settata ad uno dei valori seguenti:
\begin{errlist}
\item \macro{ENOMEM} alcuni indirizzi dell'intervallo specificato non
- corripondono allo spazio di indirizzi del processo.
+ corrispondono allo spazio di indirizzi del processo.
\item \macro{EINVAL} \var{len} non è un valore positivo.
\end{errlist}
\end{functions}
Il parametro \var{flags} di \func{mlockall} permette di controllarne il
comportamento; esso può essere specificato come l'OR aritmetico delle due
costanti:
-\begin{description*}
-\item \macro{MCL\_CURRENT} blocca tutte le pagine correntemente mappate nello
+\begin{basedescript}{\desclabelwidth{2.5cm}}
+\item[\macro{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[\macro{MCL\_FUTURE}] blocca tutte le pagine che saranno mappate nello
spazio di indirizzi del processo.
-\end{description*}
+\end{basedescript}
Con \func{mlockall} si può bloccare tutte le pagine mappate nello spazio di
indirizzi del processo, sia che comprendano il segmento di testi, di dati, lo
variabili che normalmente sono definite dal sistema, è riportato in \nfig.
\begin{figure}[htb]
\centering
- \includegraphics[width=11cm]{img/environ_var.eps}
+ \includegraphics[width=11cm]{img/environ_var}
\caption{Esempio di lista delle variabili di ambiente.}
\label{fig:proc_envirno_list}
\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 convezione di usare nomi espressi in
+funzioni: per queste c'è l'ulteriore convenzione di usare nomi espressi in
caratteri maiuscoli.
Il kernel non usa mai queste variabili, il loro uso e la loro interpretazione è
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 parziale si può controllare \cmd{man environ}.
+anche altre: per una lista più completa si può controllare \cmd{man environ}.
+\begin{table}[htb]
+ \centering
+ \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 utente\\
+ \macro{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 di default\\
+ \macro{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser di default\\
+ \hline
+ \end{tabular}
+ \caption{Variabile di ambiente più comuni definite da vari standard}
+ \label{tab:proc_env_var}
+\end{table}
+
+Lo standard ANSI C, 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}.
+
+ La funzione \macro{NULL} se non trova nulla, o il puntatore alla stringa che
+ corrisponde (di solito nella forma \texttt{NOME=valore}).
+\end{prototype}
+Oltre a questa funzione di lettura, che è l'unica definita dallo standard ANSI
+C, in seguito sono state proposte altre da utilizzare per settare e per
+cancellare le variabili di ambiente presenti; uno schema delle funzioni
+previste nei vari standard unix e disponibili in Linux è riportato in \ntab.
+
+\begin{table}[htb]
+ \centering
+ \begin{tabular}[c]{|l|c|c|c|c|c|c|}
+ \hline
+ \textbf{Funzione} & \textbf{ANSI C} & \textbf{POSIX.1} & \textbf{XPG3} &
+ \textbf{SVr4} & \textbf{BSD} & \textbf{Linux} \\
+ \hline
+ \hline
+ \func{getenv} & $\bullet$ & $\bullet$ & $\bullet$ &
+ $\bullet$ & $\bullet$ & $\bullet$ \\
+ \func{setenv} & & & &
+ & $\bullet$ & $\bullet$ \\
+ \func{unsetenv} & & & &
+ & $\bullet$ & $\bullet$ \\
+ \func{putenv} & & opz. & $\bullet$ &
+ & $\bullet$ & $\bullet$ \\
+ \func{clearenv} & & opz. & &
+ & & \\
+ \hline
+ \end{tabular}
+ \caption{Funzioni per la gestione delle variabili di ambiente.}
+ \label{tab:proc_env_func}
+\end{table}
+
+In Linux solo le prime quattro funzioni di \curtab\ sono definite; i prototipi
+delle restanti tre sono i seguenti:
+
+\begin{functions}
+ \headdecl{stdlib.h}
+ \funcdecl{int putenv(char *string)}
+ La funzione aggiunge la stringa \param{string} all'ambiente.
+ \funcdecl{int setenv(const char *name, const char *value, int overwrite)}
+ La funzione setta la variabile di ambiente \param{name} al valore
+ \param{value}.
+
+ Entrambe le funzioni ritornano 0 in caso di successo e -1 per un errore, che
+ è sempre \macro{ENOMEM}.
+
+ \funcdecl{void unsetenv(const char *name)}
+ La funzione rimuove la variabile di ambiente \param{name}.
+\end{functions}
+
+Per cancellare una variabile di ambiente si usa \func{unsetenv}, che elimina
+ogni occorrenza della variabile, se la variabile specificata non esiste non
+succede nulla, e non è previsto (dato che la funzione è \type{void}) nessuna
+segnalazione di errore.
+
+Per modificare o aggiungere una variabile di ambiente si possono usare le
+funzioni \func{setenv} e \func{putenv}. La prima permette di specificare
+separatamente nome e valore della variabile di ambiente, inoltre il valore di
+\param{overwrite} specifica il comportamento della funzione nel caso la
+variabile esista già, sovrascrivendola se diverso da zero, lasciandola
+immutata se uguale a zero.
+
+La seconda funzione prende come parametro una stringa analoga quella
+restituita da \func{getenv}, e sempre nella forma \texttt{NOME=valore}. Se la
+variabile specificata non esiste la stringa sarà aggiunta all'ambiente, se
+invece esiste il suo valore sarà settato a quello specificato da
+\func{string}. Si tenga presente che, seguendo lo standard SUSv2, le
+\acr{glibc} successive alla versione 2.1.2 aggiungono\footnote{il
+ comportamento è lo stesso delle vecchie \acr{libc4} e \acr{libc5}; nelle
+ \acr{glibc}, dalla versione 2.0 alla 2.1.1, veniva invece fatta una copia,
+ seguendo il comportamento di BSD4.4; dato che questo può dar luogo a perdite
+ di memoria e non rispetta lo standard il comportamento è stato modificato a
+ partire dalle 2.1.2, eliminando anche, sempre in conformità a SUSv2,
+ l'attributo \type{const} dal prototipo.} \func{string} alla lista delle
+variabili di ambiente; pertanto ogni cambiamento alla stringa in questione si
+riflette automaticamente sull'ambiente, e quindi si deve evitare di passare
+alla funzione variabili automatiche (per evitare i problemi esposti in
+\secref{sec:proc_auto_var}).
+
+Si tenga infine presente che se si passa a \func{putenv} solo il nome di una
+variabile (cioè \param{string} è nella forma \texttt{NAME} e non contiene un
+\var{=}) allora questa viene cancellata dall'ambiente. Infine se la chiamata
+di \func{putenv} comporta la necessità di allocare una nuova versione del
+vettore \var{environ} questo sarà allocato, ma la versione corrente sarà
+deallocata solo se anch'essa risultante da una allocazione fatta in precedenza
+da un'altra \func{putenv}, il vettore originale (in genere piazzato al di
+sopra dello stack, vedi \figref{fig:proc_mem_layout}), o la memoria associata
+alle variabili di ambiente eliminate non viene comunque liberata.
\section{Problematiche di programmazione generica}
Il C però non consente di effettuare un salto ad una label definita in
un'altra funzione, per cui se l'errore avviene in funzioni profondamente
-annidate occorre usare la funzione \func{longjump}.
+annidate occorre usare la funzioni \func{setjmp} e \func{longjmp}, il cui
+prototipo è:
+
+\begin{functions}
+ \headdecl{setjmp.h}
+ \funcdecl{void setjmp(jmp\_buf env)}
+
+ La funzione salva il contesto dello stack in \param{env} per un successivo
+ uso da parte di \func{longjmp}. Il contesto viene invalidato se la routine
+ che ha chiamato \func{setjmp} ritorna.
+
+ La funzione ritorna zero quando è chiamata direttamente e un valore diverso
+ da zero quando ritorna da una chiamata di \func{longjmp} che usa il contesto
+ salvato in precedenza.
+ \funcdecl{void longjmp(jmp\_buf env, int val)}
+
+ Ripristina il contesto dello stack salvato dall'ultima chiamata di
+ \func{setjmp} con l'argomento \param{env}. Il programma prosegue dal ritorno
+ di \func{setjmp} con un valore \param{val}. Il valore di \param{val} deve
+ essere diverso da zero, se viene specificato 0 sarà usato 1 al suo posto.
+
+ La funzione non ritorna.
+\end{functions}