%% process.tex
%%
%% Copyright (C) 2000-2005 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 "Un preambolo",
%% 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}

Come accennato nell'introduzione il \textsl{processo} è l'unità di base con
cui un sistema unix-like alloca ed utilizza le risorse.  Questo capitolo
tratterà l'interfaccia base fra il sistema e i processi, come vengono passati
gli argomenti, come viene gestita e allocata la memoria, come un processo può
richiedere servizi al sistema e cosa deve fare quando ha finito la sua
esecuzione. Nella sezione finale accenneremo ad alcune problematiche generiche
di programmazione.

In genere un programma viene eseguito quando un processo lo fa partire
eseguendo una funzione della famiglia \func{exec}; torneremo su questo e sulla
creazione e gestione dei processi nel prossimo capitolo. In questo
affronteremo l'avvio e il funzionamento di un singolo processo partendo dal
punto di vista del programma che viene messo in esecuzione.


\section{Esecuzione e conclusione di un programma}

Uno dei concetti base di Unix è che un processo esegue sempre uno ed un solo
programma: si possono avere più processi che eseguono lo stesso programma ma
ciascun processo vedrà la sua copia del codice (in realtà il kernel fa sì che
tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi,
variabili proprie e sarà eseguito in maniera completamente indipendente da
tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma
  \textit{multi-thread}, ma la gestione dei \textit{thread} in Linux sarà
  trattata a parte.}


\subsection{La funzione \func{main}} 
\label{sec:proc_main}

Quando un programma viene lanciato il kernel esegue un'opportuna routine di
avvio, usando il programma \cmd{ld-linux.so}.  Questo programma prima carica
le librerie condivise che servono al programma, poi effettua il collegamento
dinamico del codice e alla fine lo esegue. Infatti, a meno di non aver
specificato il flag \texttt{-static} durante la compilazione, tutti i
programmi in Linux sono incompleti e necessitano di essere \textsl{collegati}
alle librerie condivise quando vengono avviati.  La procedura è controllata da
alcune variabili di ambiente e dal contenuto di \file{/etc/ld.so.conf}. I
dettagli sono riportati nella man page di \cmd{ld.so}.

Il sistema fa partire qualunque programma chiamando la funzione \func{main};
sta al programmatore chiamare così la funzione principale del programma da cui
si suppone iniziare l'esecuzione; in ogni caso senza questa funzione lo stesso
\textit{linker} (ci chiama così il programma che effettua i collegamenti di
cui sopra) darebbe luogo ad errori.  Lo standard ISO C specifica che la
funzione \func{main} può non avere argomenti o prendere due argomenti che
rappresentano gli argomenti passati da linea di comando, in sostanza un
prototipo che va sempre bene è il seguente:
\includecodesnip{listati/main_def.c}

In realtà nei sistemi Unix esiste un'altro modo per definire la funzione
\func{main}, che prevede la presenza di un terzo argomento, \code{char
  *envp[]}, che fornisce (vedi sez.~\ref{sec:proc_environ})
l'\textsl{ambiente} del programma; questa forma però non è prevista dallo
standard POSIX.1 per cui se si vogliono scrivere programmi portabili è meglio
evitarla.


\subsection{Come chiudere un programma}
\label{sec:proc_conclusion}

Normalmente un programma finisce quando la funzione \func{main} ritorna, una
modalità equivalente di chiudere il programma è quella di chiamare
direttamente la funzione \func{exit} (che viene comunque chiamata
automaticamente quando \func{main} ritorna).  Una forma alternativa è quella
di chiamare direttamente la system call \func{\_exit}, che restituisce il
controllo direttamente alla routine di conclusione dei processi del kernel.

Oltre alla conclusione ``\textsl{normale}'' esiste anche la possibilità di una
conclusione ``\textsl{anomala}'' del programma a causa della ricezione di un
segnale (si veda cap.~\ref{cha:signals}) o della chiamata alla funzione
\func{abort}; torneremo su questo in sez.~\ref{sec:proc_termination}.

Il valore di ritorno della funzione \func{main}, o quello usato nelle chiamate
ad \func{exit} e \func{\_exit}, viene chiamato \textsl{stato di uscita} (o
\textit{exit status}) e passato al processo che aveva lanciato il programma
(in genere la shell). In generale si usa questo valore per fornire
informazioni sulla riuscita o il fallimento del programma; l'informazione è
necessariamente generica, ed il valore deve essere compreso fra 0 e 255.

La convenzione in uso pressoché universale è quella di restituire 0 in caso di
successo e 1 in caso di fallimento; l'unica eccezione è per i programmi che
effettuano dei confronti (come \cmd{diff}), che usano 0 per indicare la
corrispondenza, 1 per indicare la non corrispondenza e 2 per indicare
l'incapacità di effettuare il confronto. È opportuno adottare una di queste
convenzioni a seconda dei casi.  Si tenga presente che se si raggiunge la fine
della funzione \func{main} senza ritornare esplicitamente si ha un valore di
uscita indefinito, è pertanto consigliabile di concludere sempre in maniera
esplicita detta funzione.

Un'altra convenzione riserva i valori da 128 a 256 per usi speciali: ad
esempio 128 viene usato per indicare l'incapacità di eseguire un altro
programma in un sottoprocesso. Benché questa convenzione non sia
universalmente seguita è una buona idea tenerne conto.

Si tenga presente inoltre che non è una buona idea usare il codice di errore
restituito dalla variabile \var{errno} (per i dettagli si veda
sez.~\ref{sec:sys_errors}) come stato di uscita. In generale infatti una shell
non si cura del valore se non per vedere se è diverso da zero; inoltre il
valore dello stato di uscita è sempre troncato ad 8 bit, per cui si potrebbe
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 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.


\subsection{Le funzioni \func{exit} e \func{\_exit}}
\label{sec:proc_exit}

Come accennato le funzioni usate per effettuare un'uscita ``\textit{normale}''
da un 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.

  \bodydesc{La funzione non ritorna. Il processo viene terminato.}
\end{prototype}

La funzione \func{exit} è pensata per eseguire una conclusione pulita di un
programma che usi le librerie standard del C; essa esegue tutte le funzioni
che sono state registrate con \func{atexit} e \func{on\_exit} (vedi
sez.~\ref{sec:proc_atexit}), e chiude tutti gli stream effettuando il
salvataggio dei dati sospesi (chiamando \func{fclose}, vedi
sez.~\ref{sec:file_fopen}), infine passa il controllo al kernel chiamando
\func{\_exit} e restituendo il valore di \param{status} come stato di uscita.

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.

  \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 adottato da \cmd{init} (vedi
cap.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo
padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di
uscita specificato in \param{status} che può essere raccolto usando la
funzione \func{wait} (vedi sez.~\ref{sec:proc_wait}).


\subsection{Le funzioni \func{atexit} e \func{on\_exit}}
\label{sec:proc_atexit}

Un'esigenza comune che si incontra nella programmazione è quella di dover
effettuare una serie di operazioni di pulizia (ad esempio salvare dei dati,
ripristinare delle impostazioni, eliminare dei file temporanei, ecc.) prima
della conclusione di un programma. In genere queste operazioni vengono fatte
in un'apposita sezione del programma, ma quando si realizza una libreria
diventa antipatico dover richiedere una chiamata esplicita ad una funzione di
pulizia al programmatore che la utilizza.

È invece molto meno soggetto ad errori, e completamente trasparente
all'utente, avere la possibilità di effettuare automaticamente la chiamata ad
una funzione che effettui tali operazioni all'uscita dal programma. A questo
scopo lo standard ANSI C prevede la possibilità di registrare un certo numero
di 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 è \funcd{atexit} il cui prototipo è:
\begin{prototype}{stdlib.h}{void atexit(void (*function)(void))}
  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 di una opportuna
funzione di pulizia da chiamare all'uscita del programma, che non deve
prendere argomenti e non deve ritornare niente (deve essere cioè definita come
\code{void function(void)}).

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 , 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 all'uscita prende i due argomenti
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
registrata più volte sarà chiamata più volte); poi verranno chiusi tutti gli
stream aperti, infine verrà chiamata \func{\_exit}.


\subsection{Conclusioni}
\label{sec:proc_term_conclusion}

Data l'importanza dell'argomento è opportuno sottolineare ancora una volta che
in un sistema Unix l'unico modo in cui un programma può essere eseguito dal
kernel è attraverso la chiamata alla system call \func{execve} (o attraverso
una delle funzioni della famiglia \func{exec} che vedremo in
sez.~\ref{sec:proc_exec}).

Allo stesso modo l'unico modo in cui un programma può concludere
volontariamente la sua esecuzione è attraverso una chiamata alla system call
\func{\_exit}, o esplicitamente, o in maniera indiretta attraverso l'uso di
\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 fig.~\ref{fig:proc_prog_start_stop}.

\begin{figure}[htb]
  \centering
  \includegraphics[width=14cm]{img/proc_beginend}
  \caption{Schema dell'avvio e della conclusione di un programma.}
  \label{fig:proc_prog_start_stop}
\end{figure}

Si ricordi infine che un programma può anche essere interrotto dall'esterno
attraverso l'uso di un segnale (modalità di conclusione non mostrata in
fig.~\ref{fig:proc_prog_start_stop}); torneremo su questo aspetto in
cap.~\ref{cha:signals}.



\section{I processi e l'uso della memoria}
\label{sec:proc_memory}

Una delle risorse base che ciascun processo ha a disposizione è la memoria, e
la gestione della memoria è appunto uno degli aspetti più complessi di un
sistema unix-like. In questa sezione, dopo una breve introduzione ai concetti
base, esamineremo come la memoria viene vista da parte di un programma in
esecuzione, e le varie funzioni utilizzabili per la sua gestione.


\subsection{I concetti generali}
\label{sec:proc_mem_gen}

Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli
di basso livello dipendono spesso in maniera diretta dall'architettura
dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è
la cosiddetta \textsl{memoria virtuale}\index{memoria~virtuale} che consiste
nell'assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare,
in cui gli indirizzi vanno da zero ad un qualche valore massimo.\footnote{nel
  caso di Linux fino al kernel 2.2 detto massimo era, per macchine a 32bit, di
  2Gb. Con il kernel 2.4 ed il supporto per la \textit{high-memory} il limite
  è stato esteso anche per macchine a 32 bit.}

Come accennato in cap.~\ref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
computer; in genere detto spazio non è neppure continuo (cioè non tutti gli
indirizzi possibili sono utilizzabili, e quelli usabili non sono
necessariamente adiacenti).

Per la gestione da parte del kernel la memoria virtuale viene divisa in pagine
di dimensione fissa (che ad esempio sono di 4kb su macchine a 32 bit e 8kb
sulle alpha, valori strettamente connessi all'hardware di gestione della
memoria),\footnote{con le versioni più recenti del kernel è possibile anche
  utilizzare pagine di dimensioni maggiori, per sistemi con grandi
  quantitativi di memoria in cui l'uso di pagine troppo piccole comporta una
  perdita di prestazioni.} e ciascuna pagina della memoria virtuale è
associata ad un supporto che può essere una pagina di memoria reale o ad un
dispositivo di stoccaggio secondario (in genere lo spazio disco riservato alla
swap, o i file che contengono il codice).

Lo stesso pezzo di memoria reale (o di spazio disco) può fare da supporto a
diverse pagine di memoria virtuale appartenenti a processi diversi (come
accade in genere per le pagine che contengono il codice delle librerie
condivise). Ad esempio il codice della funzione \func{printf} starà su una
sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria
virtuale di tutti i processi che hanno detta funzione nel loro codice.

La corrispondenza fra le pagine della \index{memoria~virtuale}memoria virtuale
e quelle della memoria fisica della macchina viene gestita in maniera
trasparente dall'hardware di gestione della memoria (la \textit{Memory
  Management Unit} del processore).  Poiché in genere la memoria fisica è solo
una piccola frazione della memoria virtuale, è necessario un meccanismo che
permetta di trasferire le pagine che servono dal supporto su cui si trovano in
memoria, eliminando quelle che non servono. Questo meccanismo è detto
\textsl{paginazione}\index{paginazione} (o \textit{paging}), ed è uno dei
compiti principali del kernel.

Quando un processo cerca di accedere ad una pagina che non è nella memoria
reale, avviene quello che viene chiamato un \textit{page
  fault}\index{\textit{page~fault}}; l'hardware di gestione della memoria
genera un'interruzione e passa il controllo al kernel il quale sospende il
processo e si incarica di mettere in RAM la pagina richiesta (effettuando
tutte le operazioni necessarie per reperire lo spazio necessario), per poi
restituire il controllo al processo.

Dal punto di vista di un processo questo meccanismo è completamente
trasparente, e tutto avviene come se tutte le pagine fossero sempre
disponibili in memoria.  L'unica differenza avvertibile è quella dei tempi di
esecuzione, che passano dai pochi nanosecondi necessari per l'accesso in RAM,
a tempi molto più lunghi, dovuti all'intervento del kernel. 

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\index{paginazione} e
mantenere fisse delle pagine in memoria (vedi sez.~\ref{sec:proc_mem_lock}).


\subsection{La struttura della memoria di un processo}
\label{sec:proc_mem_layout}

Benché lo spazio di indirizzi virtuali copra un intervallo molto ampio, solo
una parte di essi è effettivamente allocato ed utilizzabile dal processo; il
tentativo di accedere ad un indirizzo non allocato è un tipico errore che si
commette quando si è manipolato male un puntatore e genera quello che viene
chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
scrivere da un indirizzo per il quale non esiste un'associazione della pagina
virtuale, il kernel risponde al relativo \textit{page
  fault}\index{\textit{page~fault}} mandando un segnale \const{SIGSEGV} al
processo, che normalmente ne causa la terminazione immediata.

È pertanto importante capire come viene strutturata \textsl{la memoria
  virtuale}\index{\textit{page~fault}} di un processo. Essa viene divisa in
\textsl{segmenti}, cioè un insieme contiguo di indirizzi virtuali ai quali il
processo può accedere.  Solitamente un programma C viene suddiviso nei
seguenti segmenti:

\begin{enumerate}
\item Il segmento di testo o \textit{text segment}. Contiene il codice del
  programma, delle funzioni di librerie da esso utilizzate, e le costanti.
  Normalmente viene condiviso fra tutti i processi che eseguono lo stesso
  programma (e anche da processi che eseguono altri programmi nel caso delle
  librerie).  Viene marcato in sola lettura per evitare sovrascritture
  accidentali (o maliziose) che ne modifichino le istruzioni.
  
  Viene allocato da \func{exec} all'avvio del programma e resta invariato
  per tutto il tempo dell'esecuzione.
  
\item Il segmento dei dati o \textit{data segment}. Contiene le variabili
  globali (cioè quelle definite al di fuori di tutte le funzioni che
  compongono il programma) e le variabili statiche (cioè quelle dichiarate con
  l'attributo \ctyp{static}). Di norma è diviso in due parti.
  
  La prima parte è il segmento dei dati inizializzati, che contiene le
  variabili il cui valore è stato assegnato esplicitamente. Ad esempio
  se si definisce:
\includecodesnip{listati/pi.c}
  questo valore sarà immagazzinato in questo segmento. La memoria di questo
  segmento viene preallocata all'avvio del programma e inizializzata ai valori
  specificati.
  
  La seconda parte è il segmento dei dati non inizializzati, che contiene le
  variabili il cui valore non è stato assegnato esplicitamente. Ad esempio se
  si definisce:
\includecodesnip{listati/vect.c}
  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 \val{NULL}).\footnote{si ricordi che questo vale solo per le
    variabili che vanno nel segmento dati, e non è affatto vero in generale.}
   
  Storicamente questa seconda parte del segmento dati viene chiamata BSS (da
  \textit{Block Started by Symbol}). La sua dimensione è fissa.
  
\item Lo \textit{heap}. Tecnicamente lo si può considerare l'estensione del
  segmento dati, a cui di solito è posto giusto di seguito. È qui che avviene
  l'allocazione dinamica della memoria; può essere ridimensionato allocando e
  disallocando la memoria dinamica con le apposite funzioni (vedi
  sez.~\ref{sec:proc_mem_alloc}), ma il suo limite inferiore (quello adiacente
  al segmento dati) ha una posizione fissa.
  
\item Il segmento di \textit{stack}, che contiene lo \textit{stack} del
  programma.  Tutte le volte che si effettua una chiamata ad una funzione è
  qui che viene salvato l'indirizzo di ritorno e le informazioni dello stato
  del chiamante (tipo il contenuto di alcuni registri della CPU). Poi la
  funzione chiamata alloca qui lo spazio per le sue variabili locali: in
  questo modo le funzioni possono essere chiamate ricorsivamente. Al ritorno
  della funzione lo spazio è automaticamente rilasciato e
  ``\textsl{ripulito}''. La pulizia in C e C++ viene fatta dal
  chiamante.\footnote{a meno che non sia stato specificato l'utilizzo di una
    calling convention diversa da quella standard.}
  
  La dimensione di questo segmento aumenta seguendo la crescita dello stack
  del programma, ma non viene ridotta quando quest'ultimo si restringe.
\end{enumerate}

\begin{figure}[htb]
  \centering
  \includegraphics[height=11cm]{img/memory_layout}
  \caption{Disposizione tipica dei segmenti di memoria di un processo.}
  \label{fig:proc_mem_layout}
\end{figure}

Una disposizione tipica di questi segmenti è riportata in
fig.~\ref{fig:proc_mem_layout}. Usando il comando \cmd{size} su un programma se
ne può stampare le dimensioni dei segmenti di testo e di dati (inizializzati e
BSS); si tenga presente però che il BSS non è mai salvato sul file che
contiene l'eseguibile, dato che viene sempre inizializzato a zero al
caricamento del programma.


\subsection{Allocazione della memoria per i programmi C}
\label{sec:proc_mem_alloc}

Il C supporta, a livello di linguaggio, soltanto due modalità di allocazione
della memoria: l'\textsl{allocazione statica} e l'\textsl{allocazione
  automatica}.

L'\textsl{allocazione statica} è quella con cui sono memorizzate le variabili
globali e le variabili statiche, cioè le variabili il cui valore deve essere
mantenuto per tutta la durata del programma. Come accennato queste variabili
vengono allocate nel segmento dei dati all'avvio del programma (come parte
delle operazioni svolte da \func{exec}) e lo spazio da loro occupato non viene
liberato fino alla sua conclusione.

L'\textsl{allocazione automatica} è quella che avviene per gli argomenti di
una funzione e per le sue variabili locali (le cosiddette \textsl{variabili
  automatiche}), che esistono solo per la durata della funzione.  Lo spazio
per queste variabili viene allocato nello stack quando viene eseguita la
funzione e liberato quando si esce dalla medesima.

Esiste però un terzo tipo di allocazione, l'\textsl{allocazione dinamica della
  memoria}, che non è prevista direttamente all'interno del linguaggio C, ma
che è necessaria quando il quantitativo di memoria che serve è determinabile
solo durante il corso dell'esecuzione del programma.

Il C non consente di usare variabili allocate dinamicamente, non è possibile
cioè definire in fase di programmazione una variabile le cui dimensioni
possano essere modificate durante l'esecuzione del programma. Per questo le
librerie del C forniscono una serie opportuna di funzioni per eseguire
l'allocazione dinamica di memoria (in genere nello heap). Le variabili il
cui contenuto è allocato in questo modo non potranno essere usate direttamente
come le altre, ma l'accesso sarà possibile solo in maniera indiretta,
attraverso dei puntatori.


\subsection{Le funzioni \func{malloc}, \func{calloc}, \func{realloc} e
  \func{free}}
\label{sec:proc_mem_malloc}

Le funzioni previste dallo standard ANSI C per la gestione della memoria sono
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 \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 \val{NULL} in caso di fallimento, nel qual caso
  \var{errno} assumerà il valore \errval{ENOMEM}.
\funcdecl{void *malloc(size\_t size)}
  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 \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 \param{ptr}
  portandola a \param{size}.

  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}.
\funcdecl{void free(void *ptr)}
  Disalloca lo spazio di memoria puntato da \param{ptr}.

  La funzione non ritorna nulla e non riporta errori.
\end{functions}
Il puntatore ritornato dalle funzioni di allocazione è garantito essere sempre
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 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}
  definita per compatibilità con SunOS, che è deprecata.} una volta che non
sia più necessaria. Questa funzione vuole come argomento un puntatore
restituito da una precedente chiamata a una qualunque delle funzioni di
allocazione che non sia già stato liberato da un'altra chiamata a \func{free},
in caso contrario il comportamento della funzione è indefinito.

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 \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
  consentivano di usare \func{realloc} anche per un puntatore liberato con
  \func{free} purché non ci fossero state nel frattempo altre chiamate a
  funzioni di allocazione, questa funzionalità è totalmente deprecata e non è
  consentita sotto Linux.} ad esempio quando si deve far crescere la
dimensione di un vettore. In questo caso se è disponibile dello spazio
adiacente al precedente la funzione lo utilizza, altrimenti rialloca altrove
un blocco della dimensione voluta, copiandoci automaticamente il contenuto; lo
spazio aggiunto non viene inizializzato.

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
\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 vettori di
puntatori) è quello di chiamare \func{free} più di una volta sullo stesso
puntatore; per evitare questo problema una soluzione di ripiego è quella di
assegnare sempre a \val{NULL} ogni puntatore liberato con \func{free}, dato
che, quando l'argomento è 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 di 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 sez.~\ref{sec:file_std_stream}).
\item se è posta a 2 viene chiamata \func{abort}, che in genere causa
  l'immediata conclusione del programma.
\end{itemize}

Il problema più comune e più difficile da risolvere che si incontra con le
routine di allocazione è quando non viene opportunamente liberata la memoria
non più utilizzata, quello che in inglese viene chiamato \textit{memory
  leak}\index{\textit{memory~leak}}, cioè una \textsl{perdita di memoria}.

Un caso tipico che illustra il problema è quello in cui in una subroutine si
alloca della memoria per uso locale senza liberarla prima di uscire. La
memoria resta così allocata fino alla terminazione del processo.  Chiamate
ripetute alla stessa subroutine continueranno ad effettuare altre allocazioni,
causando a lungo andare un esaurimento della memoria disponibile (e la
probabile impossibilità di proseguire l'esecuzione del programma).

Il problema è che l'esaurimento della memoria può avvenire in qualunque
momento, in corrispondenza ad una qualunque chiamata di \func{malloc}, che può
essere in una sezione del codice che non ha alcuna relazione con la subroutine
che contiene l'errore. Per questo motivo è sempre molto difficile trovare un
\textit{memory leak}\index{\textit{memory~leak}}.

In C e C++ il problema è particolarmente sentito. In C++, per mezzo della
programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente
ridimensionato attraverso l'uso accurato di appositi oggetti come gli
\textit{smartpointers}.  Questo però va a scapito delle prestazioni
dell'applicazione in esecuzione.

In altri linguaggi come il java e recentemente il C\# il problema non si pone
nemmeno perché la gestione della memoria viene fatta totalmente in maniera
automatica, ovvero il programmatore non deve minimamente preoccuparsi di
liberare la memoria allocata precedentemente quando non serve più, poiché il
framework gestisce automaticamente la cosiddetta \textit{garbage collection}.
In tal caso, attraverso meccanismi simili a quelli del \textit{reference
  counting}, quando una zona di memoria precedentemente allocata non è più
riferita da nessuna parte del codice in esecuzione, può essere deallocata
automaticamente in qualunque momento dall'infrastruttura.

Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione
(inoltre le applicazioni sviluppate con tali linguaggi di solito non sono
eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria
la presenza di una infrastruttura per la loro interpretazione e pertanto hanno
di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni
compilate direttamente).  Questo comporta però il problema della non
predicibilità del momento in cui viene deallocata la memoria precedentemente
allocata da un oggetto.

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/}{\textsf{http://dmalloc.com/}} di Gray Watson ed
  \textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche
molto complesse riguardo l'allocazione della memoria.


\subsection{Le funzioni \func{alloca}, \func{brk} e \func{sbrk}}  
\label{sec:proc_mem_sbrk_alloca}

Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in
precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
nello heap usa il segmento di stack della funzione corrente. La sintassi è
identica a quella di \func{malloc}, il suo prototipo è:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
  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}

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\index{\textit{memory~leak}},
dato che non serve più la deallocazione esplicita; inoltre la deallocazione
automatica funziona anche quando si usa \func{longjmp} per uscire da una
subroutine con un salto non locale da una funzione (vedi
sez.~\ref{sec:proc_longjmp}).

Un altro vantaggio è che in Linux la funzione è molto più veloce di
\func{malloc} e non viene sprecato spazio, infatti non è necessario gestire un
pool di memoria da riservare e si evitano così anche i problemi di
frammentazione di quest'ultimo, che comportano inefficienze sia
nell'allocazione della memoria che nell'esecuzione dell'allocazione.

Gli svantaggi sono che questa funzione non è disponibile su tutti gli Unix, e
non è inserita né nello standard POSIX né in SUSv3 (ma è presente in BSD), il
suo utilizzo quindi limita la portabilità dei programmi. Inoltre la funzione
non può essere usata nella lista degli argomenti di una funzione, perché lo
spazio verrebbe allocato nel mezzo degli stessi.

% Questo è riportato solo dal manuale delle glibc, nelle pagine di manuale non c'è 
% traccia di tutto ciò
%
%Inoltre se si
%cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma un
%segnale di \textit{segment violation} analogo a quello che si avrebbe da una
%ricorsione infinita.

Inoltre non è chiaramente possibile usare \func{alloca} per allocare memoria
che deve poi essere usata anche al di fuori della funzione in cui essa viene
chiamata, dato che all'uscita dalla funzione lo spazio allocato diventerebbe
libero, e potrebbe essere sovrascritto all'invocazione di nuove funzioni.
Questo è lo stesso problema che si può avere con le variabili automatiche, su
cui torneremo in sez.~\ref{sec:proc_auto_var}.


Queste due funzioni vengono utilizzate soltanto quando è necessario effettuare
direttamente la gestione della memoria associata allo spazio dati di un
processo, ad esempio qualora si debba implementare la propria versione delle
routine di allocazione della memoria viste in sez.~\ref{sec:proc_mem_malloc}.
La prima funzione è \funcd{brk}, ed il suo prototipo è:
\begin{prototype}{unistd.h}{int brk(void *end\_data\_segment)}
  Sposta la fine del segmento dei dati.
  
  \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}

La funzione è un'interfaccia diretta all'omonima 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 sez.~\ref{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 system call.} è \funcd{sbrk}, ed il suo prototipo è:
\begin{prototype}{unistd.h}{void *sbrk(ptrdiff\_t increment)} 
  Incrementa la dimensione dello spazio 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. 


% \subsection{La personalizzazione delle funzioni di allocazione} 
% \label{sec:proc_mem_malloc_custom}


\subsection{Il controllo della memoria virtuale}  
\label{sec:proc_mem_lock}

\index{memoria~virtuale|(}
Come spiegato in sez.~\ref{sec:proc_mem_gen} il kernel gestisce la memoria
virtuale in maniera trasparente ai processi, decidendo quando rimuovere pagine
dalla memoria per metterle nello swap, sulla base dell'utilizzo corrente da
parte dei vari processi.

Nell'uso comune un processo non deve preoccuparsi di tutto ciò, in quanto il
meccanismo della paginazione\index{paginazione} riporta in RAM, ed in maniera
trasparente, tutte le pagine che gli occorrono; esistono però esigenze
particolari in cui non si vuole che questo meccanismo si attivi. In generale i
motivi per cui si possono avere di queste necessità sono due:
\begin{itemize}
\item \textsl{La velocità}. Il processo della paginazione\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
  quali pagine di memoria è opportuno che restino in memoria per un aumento
  delle prestazioni. In genere queste sono esigenze particolari e richiedono
  anche un aumento delle priorità in esecuzione del processo (vedi
  sez.~\ref{sec:proc_real_time}).
  
\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\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}

\index{\textit{memory~locking}|(}
Il meccanismo che previene la paginazione\index{paginazione} di parte della
memoria virtuale di un processo è chiamato \textit{memory locking} (o
\textsl{blocco della memoria}). Il blocco è sempre associato alle pagine della
memoria virtuale del processo, e non al segmento reale di RAM su cui essa
viene mantenuta.

La regola è che se un segmento di RAM fa da supporto ad almeno una pagina
bloccata allora esso viene escluso dal meccanismo della
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}.  Infine \textit{memory lock} non sono
ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on
    write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio
  sono mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che
  un figlio non scrive su un segmento, può usufruire del \textit{memory lock}
  del padre.}

Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce
la memoria fisica disponibile nel sistema, questo ha un evidente impatto su
tutti gli altri processi, per cui solo un processo con i privilegi di
amministratore (vedremo in sez.~\ref{sec:proc_perms} cosa significa) ha la
capacità di bloccare una pagina.  Ogni processo può però sbloccare le pagine
relative alla propria memoria.

Il sistema pone dei limiti all'ammontare di memoria di un processo che può
essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo
standard POSIX.1 richiede che sia definita in \file{unistd.h} la macro
\macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il
\textit{memory locking} e la costante \const{PAGESIZE} in \file{limits.h} per
indicare la dimensione di una pagina in byte.

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 su un intervallo di memoria.

  \funcdecl{int munlock(const void *addr, size\_t len)}
  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[\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[\errcode{EINVAL}] \param{len} non è un valore positivo.
  \end{errlist}
  e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i
  privilegi richiesti per l'operazione.}
\end{functions}

Le due funzioni permettono rispettivamente di bloccare e sbloccare la
paginazione\index{paginazione} per l'intervallo di memoria specificato dagli
argomenti, che ne indicano nell'ordine l'indirizzo iniziale e la lunghezza.
Tutte le pagine che contengono una parte dell'intervallo bloccato sono
mantenute in RAM per tutta la durata del blocco.

Altre due funzioni, \funcd{mlockall} e \funcd{munlockall}, consentono 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} 

  \funcdecl{int mlockall(int flags)}
  Blocca la paginazione per lo spazio di indirizzi del processo corrente. 
  
  \funcdecl{int munlockall(void)}
  Sblocca la paginazione per lo spazio di indirizzi del processo corrente. 
  
  \bodydesc{Codici di ritorno ed errori sono gli stessi di \func{mlock}
    e \func{munlock}.}
\end{functions}

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[\const{MCL\_CURRENT}] blocca tutte le pagine correntemente mappate nello
  spazio di indirizzi del processo.
\item[\const{MCL\_FUTURE}] blocca tutte le pagine che verranno mappate nello
  spazio di indirizzi del processo.
\end{basedescript}

Con \func{mlockall} si possono bloccare tutte le pagine mappate nello spazio
di indirizzi del processo, sia che comprendano il segmento di testo, di dati,
lo stack, lo heap e pure le funzioni di libreria chiamate, i file mappati in
memoria, i dati del kernel mappati in user space, la memoria condivisa.  L'uso
dei flag permette di selezionare con maggior finezza le pagine da bloccare, ad
esempio limitandosi a tutte le pagine allocate a partire da un certo momento.

In ogni caso un processo real-time che deve entrare in una sezione critica
deve provvedere a riservare memoria sufficiente prima dell'ingresso, per
scongiurare l'occorrenza di un eventuale \textit{page
  fault}\index{\textit{page~fault}} causato dal meccanismo di \textit{copy on
  write}\index{\textit{copy~on~write}}.  Infatti se nella sezione critica si
va ad utilizzare memoria che non è ancora stata riportata in RAM si potrebbe
avere un page fault durante l'esecuzione della stessa, con conseguente
rallentamento (probabilmente inaccettabile) dei tempi di esecuzione.

In genere si ovvia a questa problematica chiamando una funzione che ha
allocato una quantità sufficientemente ampia di variabili automatiche, in modo
che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri
che esse siano state effettivamente portate in memoria, ci si scrive sopra.
\index{memoria~virtuale|)}
\index{\textit{memory~locking}|)}



\section{Argomenti, opzioni ed ambiente di un processo}
\label{sec:proc_options}

Tutti i programmi hanno la possibilità di ricevere argomenti e opzioni quando
vengono lanciati. Il passaggio degli argomenti è effettuato attraverso gli
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 sez.~\ref{sec:proc_exec}) quando questo
viene messo in esecuzione.

Oltre al passaggio degli argomenti, un'altra modalità che permette di passare
delle informazioni che modifichino il comportamento di un programma è quello
dell'uso del cosiddetto \textit{environment} (cioè l'uso delle
\textsl{variabili di ambiente}). In questa sezione esamineremo le funzioni che
permettono di gestire argomenti ed opzioni, e quelle che consentono di
manipolare ed utilizzare le variabili di ambiente.


\subsection{Il formato degli argomenti}
\label{sec:proc_par_format}
In genere passaggio degli argomenti al programma viene effettuato dalla shell,
che si incarica di leggere la linea di comando e di effettuarne la scansione
(il cosiddetto \textit{parsing}) per individuare le parole che la compongono,
ciascuna delle quali viene considerata un argomento. Di norma per individuare
le parole viene usato come carattere di separazione lo spazio o il tabulatore,
ma il comportamento è modificabile attraverso l'impostazione della variabile
di ambiente \cmd{IFS}.

\begin{figure}[htb]
  \centering
  \includegraphics[width=13cm]{img/argv_argc}
  \caption{Esempio dei valori di \param{argv} e \param{argc} generati nella 
    scansione di una riga di comando.}
  \label{fig:proc_argv_argc}
\end{figure}

Nella scansione viene costruito il vettore di puntatori \param{argv} inserendo
in successione il puntatore alla stringa costituente l'$n$-simo argomento; la
variabile \param{argc} viene inizializzata al numero di argomenti trovati, in
questo modo il primo argomento è sempre il nome del programma; un esempio di
questo meccanismo è mostrato in fig.~\ref{fig:proc_argv_argc}.


\subsection{La gestione delle opzioni}
\label{sec:proc_opt_handling}

In generale un programma Unix riceve da linea di comando sia gli argomenti che
le opzioni, queste ultime sono standardizzate per essere riconosciute come
tali: un elemento di \param{argv} che inizia con il carattere \texttt{'-'} e
che non sia un singolo \texttt{'-'} o un \texttt{'-{}-'} viene considerato
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
fig.~\ref{fig:proc_argv_argc}. In quel caso le opzioni sono \cmd{-r} e \cmd{-m}
e la prima vuole un parametro mentre la seconda no (\cmd{questofile.txt} è un
argomento del programma, non un parametro di \cmd{-m}).

Per gestire le opzioni all'interno dei argomenti a linea di comando passati in
\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 \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 \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 \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 fig.~\ref{fig:proc_argv_argc} ad esempio la
stringa di opzioni avrebbe dovuto contenere \texttt{"r:m"}.

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 \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 \param{argv} che cominciano con il carattere \texttt{'-'}.

\begin{figure}[htb]
  \footnotesize \centering
  \begin{minipage}[c]{15.6cm}
  \includecodesample{listati/option_code.c}
  \end{minipage}
  \normalsize
  \caption{Esempio di codice per la gestione delle opzioni.}
  \label{fig:proc_options_code}
\end{figure}

Quando la funzione trova un'opzione essa ritorna il valore numerico del
carattere, in questo modo si possono eseguire azioni specifiche usando uno
\code{switch}; \func{getopt} inoltre inizializza alcune variabili globali:
\begin{itemize*}
\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 \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.
\end{itemize*}

In fig.~\ref{fig:proc_options_code} è mostrata la sezione del programma
\file{ForkTest.c} (che useremo nel prossimo capitolo per effettuare dei test
sulla creazione dei processi) deputata alla decodifica delle opzioni a riga di
comando. 

Si può notare che si è anzitutto (\texttt{\small 1}) disabilitata la stampa di
messaggi di errore per opzioni non riconosciute, per poi passare al ciclo per
la verifica delle opzioni (\texttt{\small 2-27}); per ciascuna delle opzioni
possibili si è poi provveduto ad un'azione opportuna, ad esempio per le tre
opzioni che prevedono un parametro si è effettuata la decodifica del medesimo
(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 \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}
\label{sec:proc_opt_extended}

Un'estensione di questo schema è costituito dalle cosiddette
\textit{long-options} espresse nella forma \cmd{-{}-option=parameter}, anche
la gestione di queste ultime è stata standardizzata attraverso l'uso di una
versione estesa di \func{getopt}.

(NdA: questa parte verrà inserita in seguito).


\subsection{Le variabili di ambiente}
\label{sec:proc_environ}

Oltre agli argomenti passati a linea di comando ogni processo riceve dal
sistema un \textsl{ambiente}, nella forma di una lista di variabili (detta
\textit{environment list}) messa a disposizione dal processo, e costruita
nella chiamata alla funzione \func{exec} quando questo viene lanciato.

Come per la lista degli argomenti anche questa lista è un vettore di puntatori
a caratteri, ciascuno dei quali punta ad una stringa, terminata da un
\val{NULL}. A differenza di \code{argv[]} in questo caso non si ha una
lunghezza del vettore 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
variabile globale \var{environ}, a cui si può accedere attraverso una semplice
dichiarazione del tipo:
\includecodesnip{listati/env_ptr.c}
un esempio della struttura di questa lista, contenente alcune delle variabili
più comuni che normalmente sono definite dal sistema, è riportato in
fig.~\ref{fig:proc_envirno_list}.
\begin{figure}[htb]
  \centering
  \includegraphics[width=13cm]{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 fig.~\ref{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. É 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 sez.~\ref{sec:proc_exec}).

La shell ad esempio ne usa molte per il suo funzionamento (come \texttt{PATH}
per la ricerca dei comandi, o \texttt{IFS} per la scansione degli argomenti),
e alcune di esse (come \texttt{HOME}, \texttt{USER}, etc.) sono definite al
login (per i dettagli si veda sez.~\ref{sec:sess_login}). In genere è cura
dell'amministratore definire le opportune variabili di ambiente in uno script
di avvio. Alcune servono poi come riferimento generico per molti programmi
(come \texttt{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 tab.~\ref{tab:proc_env_var}. GNU/Linux le supporta
tutte e ne definisce anche altre: per una lista più completa si può
controllare \cmd{man environ}.

\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
    \texttt{USER}   &$\bullet$&$\bullet$&$\bullet$& Nome utente\\
    \texttt{LOGNAME}&$\bullet$&$\bullet$&$\bullet$& Nome di login\\
    \texttt{HOME}   &$\bullet$&$\bullet$&$\bullet$& Directory base
                                                    dell'utente\\
    \texttt{LANG}   &$\bullet$&$\bullet$&$\bullet$& Localizzazione\\
    \texttt{PATH}   &$\bullet$&$\bullet$&$\bullet$& Elenco delle directory
                                                    dei programmi\\
    \texttt{PWD}    &$\bullet$&$\bullet$&$\bullet$& Directory corrente\\
    \texttt{SHELL}  &$\bullet$&$\bullet$&$\bullet$& Shell in uso\\
    \texttt{TERM}   &$\bullet$&$\bullet$&$\bullet$& Tipo di terminale\\
    \texttt{PAGER}  &$\bullet$&$\bullet$&$\bullet$& Programma per vedere i
                                                    testi\\
    \texttt{EDITOR} &$\bullet$&$\bullet$&$\bullet$& Editor preferito\\
    \texttt{BROWSER}&$\bullet$&$\bullet$&$\bullet$& Browser preferito\\
    \texttt{TMPDIR} &$\bullet$&$\bullet$&$\bullet$& Directory dei file
                                                    temporanei\\
    \hline
  \end{tabular}
  \caption{Esempi delle 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, 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 \val{NULL} se non trova nulla, o il
    puntatore alla stringa che corrisponde (di solito nella forma
    \cmd{NOME=valore}).}
\end{prototype}

Oltre a questa funzione di lettura, che è l'unica definita dallo standard ANSI
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 tab.~\ref{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} & 
    \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.      &   --
                   &    --     &    --     & $\bullet$ \\
    \hline
  \end{tabular}
  \caption{Funzioni per la gestione delle variabili di ambiente.}
  \label{tab:proc_env_func}
\end{table}

In Linux\footnote{in realtà nelle libc4 e libc5 sono definite solo le prime
  quattro, \func{clearenv} è stata introdotta con le \acr{glibc} 2.0.} sono
definite tutte le funzioni elencate in tab.~\ref{tab:proc_env_func}. La prima,
\func{getenv}, l'abbiamo appena esaminata; delle 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} 
  
  \funcdecl{int setenv(const char *name, const char *value, int overwrite)}
  Imposta la variabile di ambiente \param{name} al valore \param{value}.
  
  \funcdecl{int putenv(char *string)} Aggiunge la stringa \param{string}
  all'ambiente.
  
  \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 per un
    errore, che è sempre \errval{ENOMEM}.}
\end{functions}
\noindent la terza, \funcd{unsetenv}, serve a cancellare una variabile di
ambiente; il suo prototipo è:
\begin{functions}
  \headdecl{stdlib.h}
  
  \funcdecl{void unsetenv(const char *name)} Rimuove la variabile di ambiente
  \param{name}.
\end{functions}
\noindent questa funzione elimina ogni occorrenza della variabile specificata;
se essa non esiste non succede nulla. Non è prevista (dato che la funzione è
\ctyp{void}) nessuna segnalazione di errore.

Per modificare o aggiungere una variabile di ambiente si possono usare sia
\func{setenv} che \func{putenv}. La prima permette di specificare
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 argomento una stringa analoga quella
restituita da \func{getenv}, e sempre nella forma \code{NOME=valore}. Se la
variabile specificata non esiste la stringa sarà aggiunta all'ambiente, se
invece esiste il suo valore sarà impostato a quello specificato da
\param{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 \direct{const} dal prototipo.} \param{string} alla lista delle
variabili di ambiente; pertanto ogni cambiamento alla stringa in questione si
riflette automaticamente sull'ambiente, e quindi si deve evitare di passare a
questa funzione una variabile automatica (per evitare i problemi esposti in
sez.~\ref{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
carattere \texttt{'='}) 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 un'allocazione
fatta in precedenza da un'altra \func{putenv}. Questo perché il vettore delle
variabili di ambiente iniziale, creato dalla chiamata ad \func{exec} (vedi
sez.~\ref{sec:proc_exec}) è piazzato al di sopra dello stack, (vedi
fig.~\ref{fig:proc_mem_layout}) e non nello heap e non può essere deallocato.
Inoltre la memoria associata alle variabili di ambiente eliminate non viene
liberata.

L'ultima funzione è \funcd{clearenv}, che viene usata per cancellare
completamente tutto l'ambiente; il suo prototipo è:
\begin{functions}
  \headdecl{stdlib.h}
  
  \funcdecl{int clearenv(void)} 
  Cancella tutto l'ambiente.
  
  \bodydesc{la funzione restituisce 0 in caso di successo e un valore diverso
    da zero per un errore.}
\end{functions}

In genere si usa questa funzione in maniera precauzionale per evitare i
problemi di sicurezza connessi nel trasmettere ai programmi che si invocano un
ambiente che può contenere dei dati non controllati. In tal caso si provvede
alla cancellazione di tutto l'ambiente per costruirne una versione
``\textsl{sicura}'' da zero.


\section{Problematiche di programmazione generica}
\label{sec:proc_gen_prog}

Benché questo non sia un libro di C, è opportuno affrontare alcune delle
problematiche generali che possono emergere nella programmazione e di quali
precauzioni o accorgimenti occorre prendere per risolverle. Queste
problematiche non sono specifiche di sistemi unix-like o multitasking, ma
avendo trattato in questo capitolo il comportamento dei processi visti come
entità a sé stanti, le riportiamo qui.


\subsection{Il passaggio delle variabili e dei valori di ritorno}
\label{sec:proc_var_passing}

Una delle caratteristiche standard del C è che le variabili vengono passate
alle subroutine attraverso un meccanismo che viene chiamato \textit{by value}
(diverso ad esempio da quanto avviene con il Fortran, dove le variabili sono
passate, come suol dirsi, \textit{by reference}, o dal C++ dove la modalità
del passaggio può essere controllata con l'operatore \cmd{\&}).

Il passaggio di una variabile \textit{by value} significa che in realtà quello
che viene passato alla subroutine è una copia del valore attuale di quella
variabile, copia che la subroutine potrà modificare a piacere, senza che il
valore originale nella routine chiamante venga toccato. In questo modo non
occorre preoccuparsi di eventuali effetti delle operazioni della subroutine
sulla variabile passata come argomento.

Questo però va inteso nella maniera corretta. Il passaggio \textit{by value}
vale per qualunque variabile, puntatori compresi; quando però in una
subroutine si usano dei puntatori (ad esempio per scrivere in un buffer) in
realtà si va a modificare la zona di memoria a cui essi puntano, per cui anche
se i puntatori sono copie, i dati a cui essi puntano sono sempre gli stessi, e
le eventuali modifiche avranno effetto e saranno visibili anche nella routine
chiamante.

Nella maggior parte delle funzioni di libreria e delle system call i puntatori
vengono usati per scambiare dati (attraverso buffer o strutture) e le
variabili semplici vengono usate per specificare argomenti; in genere le
informazioni a riguardo dei risultati vengono passate alla routine chiamante
attraverso il valore di ritorno.  È buona norma seguire questa pratica anche
nella programmazione normale.

Talvolta però è necessario che la funzione possa restituire indietro alla
funzione chiamante un valore relativo ad uno dei suoi argomenti.  Per far
questo si usa il cosiddetto
\index{\textit{value~result~argument}}\textit{value result argument}, si passa
cioè, invece di una normale variabile, un puntatore alla stessa; vedremo
alcuni esempi di questa modalità nelle funzioni che gestiscono i socket (in
sez.~\ref{sec:TCP_functions}), in cui, per permettere al kernel di restituire
informazioni sulle dimensioni delle strutture degli indirizzi utilizzate,
viene usato questo meccanismo.


\subsection{Il passaggio di un numero variabile di argomenti}
\label{sec:proc_variadic}

Come vedremo nei capitoli successivi, non sempre è possibile specificare un
numero fisso di argomenti per una funzione.  Lo standard ISO C prevede nella
sua sintassi la possibilità di definire delle \textit{variadic
  function}\index{variadic} che abbiano un numero variabile di argomenti,
attraverso l'uso nella dichiarazione della funzione dello speciale costrutto
``\texttt{...}'', che viene chiamato \textit{ellipsis}.  

Lo standard però non provvede a livello di linguaggio alcun meccanismo con cui
dette funzioni possono accedere ai loro argomenti.  L'accesso viene pertanto
realizzato a livello delle librerie standard del C che provvedono gli
strumenti adeguati.  L'uso di una \textit{variadic function} prevede quindi
tre punti:
\begin{itemize}
\item \textsl{Dichiarare} la funzione come \textit{variadic} usando un
  prototipo che contenga una \textit{ellipsis}.
\item \textsl{Definire} la funzione come \textit{variadic} usando la stessa
  \textit{ellipsis}, ed utilizzare le apposite macro che consentono la
  gestione di un numero variabile di argomenti.
\item \textsl{Invocare} la funzione specificando prima gli argomenti fissi, ed
  a seguire quelli addizionali.
\end{itemize}

Lo standard ISO C prevede che una \textit{variadic function}\index{variadic}
abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione
deve essere incluso l'apposito header file \file{stdarg.h}; un esempio di
dichiarazione è il prototipo della funzione \func{execl} che vedremo in
sez.~\ref{sec:proc_exec}:
\includecodesnip{listati/exec_sample.c}
in questo caso la funzione prende due argomenti fissi ed un numero variabile
di altri argomenti (che verranno a costituire gli elementi successivi al primo
del vettore \param{argv} passato al nuovo processo). Lo standard ISO C
richiede inoltre che l'ultimo degli argomenti fissi sia di tipo
\textit{self-promoting}\footnote{il linguaggio C prevede che quando si
  mescolano vari tipi di dati, alcuni di essi possano essere \textsl{promossi}
  per compatibilità; ad esempio i tipi \ctyp{float} vengono convertiti
  automaticamente a \ctyp{double} ed i \ctyp{char} e gli \ctyp{short} ad
  \ctyp{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso
  a sé stesso.} il che esclude vettori, puntatori a funzioni e interi di tipo
\ctyp{char} o \ctyp{short} (con segno o meno). Una restrizione ulteriore di
alcuni compilatori è di non dichiarare l'ultimo argomento fisso come
\direct{register}.

Una volta dichiarata la funzione il secondo passo è accedere ai vari argomenti
quando la si va a definire. Gli argomenti fissi infatti hanno un loro nome, ma
quelli variabili vengono indicati in maniera generica dalla \textit{ellipsis}.

L'unica modalità in cui essi possono essere recuperati è pertanto quella
sequenziale; essi verranno estratti dallo stack secondo l'ordine in cui sono
stati scritti. Per fare questo in \file{stdarg.h} sono definite delle apposite
macro; la procedura da seguire è la seguente:
\begin{enumerate}
\item Inizializzare un puntatore alla lista degli argomenti di tipo
  \macro{va\_list} attraverso la macro \macro{va\_start}.
\item Accedere ai vari argomenti opzionali con chiamate successive alla macro
  \macro{va\_arg}, la prima chiamata restituirà il primo argomento, la seconda
  il secondo e così via.
\item Dichiarare la conclusione dell'estrazione degli argomenti invocando la
  macro \macro{va\_end}.
\end{enumerate}
in generale è perfettamente legittimo richiedere meno argomenti di quelli che
potrebbero essere stati effettivamente forniti, e nella esecuzione delle
\macro{va\_arg} ci si può fermare in qualunque momento ed i restanti argomenti
saranno ignorati; se invece si richiedono più argomenti di quelli forniti si
otterranno dei valori indefiniti. Nel caso del \cmd{gcc} l'uso della macro
\macro{va\_end} è inutile, ma si consiglia di usarlo ugualmente per
compatibilità.

Le definizioni delle tre macro sono le seguenti:
\begin{functions}
  \headdecl{stdarg.h}
  
  \funcdecl{void va\_start(va\_list ap, last)} Inizializza il puntatore alla
  lista di argomenti \param{ap}; il parametro \param{last} \emph{deve} essere
  l'ultimo degli argomenti fissi.
  
  \funcdecl{type va\_arg(va\_list ap, type)} Restituisce il valore del
  successivo argomento opzionale, modificando opportunamente \param{ap}; la
  macro richiede che si specifichi il tipo dell'argomento attraverso il
  parametro \param{type} che deve essere il nome del tipo dell'argomento in
  questione. Il tipo deve essere \textit{self-promoting}.

  \funcdecl{void va\_end(va\_list ap)} Conclude l'uso di \param{ap}.
\end{functions}

In generale si possono avere più puntatori alla lista degli argomenti,
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 \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 dell'argomento.

Un altro limite delle macro è che i passi 1) e 3) devono essere eseguiti nel
corpo principale della funzione, il passo 2) invece può essere eseguito anche
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 \param{ap} risulterebbe indefinito.

Esistono dei casi in cui è necessario eseguire più volte la scansione degli
argomenti e poter memorizzare una posizione durante la stessa.  La cosa più
naturale in questo caso sembrerebbe quella di copiarsi il puntatore alla lista
degli argomenti con una semplice assegnazione. Dato che una delle
realizzazioni più comuni di \macro{va\_list} è quella di un puntatore nello
stack all'indirizzo dove sono stati salvati gli argomenti, è assolutamente
normale pensare di poter effettuare questa operazione.

In generale però possono esistere anche realizzazioni diverse, per questo
motivo \macro{va\_list} è definito come \textsl{tipo opaco}\index{tipo!opaco}
e non può essere assegnato direttamente ad un'altra variabile dello stesso
tipo. Per risolvere questo problema lo standard ISO C99\footnote{alcuni
  sistemi che non hanno questa macro provvedono al suo posto
  \macro{\_\_va\_copy} che era il nome proposto in una bozza dello standard.}
ha previsto una macro ulteriore che permette di eseguire la copia di un
puntatore alla lista degli argomenti:
\begin{prototype}{stdarg.h}{void va\_copy(va\_list dest, va\_list src)}
  Copia l'attuale valore \param{src} del puntatore alla lista degli argomenti
  su \param{dest}.
\end{prototype}
\noindent anche in questo caso è buona norma chiudere ogni esecuzione di una
\macro{va\_copy} con una corrispondente \macro{va\_end} sul nuovo puntatore
alla lista degli argomenti.

La chiamata di una funzione con un numero variabile di argomenti, posto che la
si sia dichiarata e definita come tale, non prevede nulla di particolare;
l'invocazione è identica alle altre, con gli argomenti, sia quelli fissi che
quelli opzionali, separati da virgole. Quello che però è necessario tenere
presente è come verranno convertiti gli argomenti variabili.

In Linux gli argomenti dello stesso tipo sono passati allo stesso modo, sia
che siano fissi sia che siano opzionali (alcuni sistemi trattano diversamente
gli opzionali), ma dato che il prototipo non può specificare il tipo degli
argomenti opzionali, questi verranno sempre promossi, pertanto nella ricezione
dei medesimi occorrerà tenerne conto (ad esempio un \ctyp{char} verrà visto da
\macro{va\_arg} come \ctyp{int}).

Uno dei problemi che si devono affrontare con le funzioni con un numero
variabile di argomenti è che non esiste un modo generico che permetta di
stabilire quanti sono gli argomenti passati effettivamente in una chiamata.

Esistono varie modalità per affrontare questo problema; una delle più
immediate è quella di specificare il numero degli argomenti opzionali come uno
degli argomenti fissi. Una variazione di questo metodo è l'uso di un argomento
per specificare anche il tipo degli argomenti (come fa la stringa di formato
per \func{printf}).

Una modalità diversa, che può essere applicata solo quando il tipo degli
argomenti lo rende possibile, è quella che prevede di usare un valore speciale
come ultimo argomento (come fa ad esempio \func{execl} che usa un puntatore
\val{NULL} per indicare la fine della lista degli argomenti).


\subsection{Potenziali problemi con le variabili automatiche}
\label{sec:proc_auto_var}

Uno dei possibili problemi che si possono avere con le subroutine è quello di
restituire alla funzione chiamante dei dati che sono contenuti in una
variabile automatica.  Ovviamente quando la subroutine ritorna la sezione
dello stack che conteneva la variabile automatica potrà essere riutilizzata da
una nuova funzione, con le immaginabili conseguenze di sovrapposizione e
sovrascrittura dei dati.

Per questo una delle regole fondamentali della programmazione in C è che
all'uscita di una funzione non deve restare nessun riferimento alle variabili
locali; qualora sia necessario utilizzare variabili che possano essere viste
anche dalla funzione chiamante queste devono essere allocate esplicitamente, o
in maniera statica (usando variabili di tipo \ctyp{static} o \ctyp{extern}), o
dinamicamente con una delle funzioni della famiglia \func{malloc}.


\subsection{Il controllo di flusso non locale}
\label{sec:proc_longjmp}

Il controllo del flusso di un programma in genere viene effettuato con le
varie istruzioni del linguaggio C; fra queste la più bistrattata è il
\code{goto}, che viene deprecato in favore dei costrutti della programmazione
strutturata, che rendono il codice più leggibile e mantenibile. Esiste però un
caso in cui l'uso di questa istruzione porta all'implementazione più
efficiente e più chiara anche dal punto di vista della struttura del
programma: quello dell'uscita in caso di errore.

\index{salto~non-locale|(} 

Il C però non consente di effettuare un salto ad una etichetta definita in
un'altra funzione, per cui se l'errore avviene in una funzione, e la sua
gestione ordinaria è in un'altra, occorre usare quello che viene chiamato un
\textsl{salto non-locale}.  Il caso classico in cui si ha questa necessità,
citato sia in \cite{APUE} che in \cite{glibc}, è quello di un programma nel
cui corpo principale vengono letti dei dati in ingresso sui quali viene
eseguita, tramite una serie di funzioni di analisi, una scansione dei
contenuti, da cui si ottengono le indicazioni per l'esecuzione di opportune
operazioni.

Dato che l'analisi può risultare molto complessa, ed opportunamente suddivisa
in fasi diverse, la rilevazione di un errore nei dati in ingresso può accadere
all'interno di funzioni profondamente annidate l'una nell'altra. In questo
caso si dovrebbe gestire, per ciascuna fase, tutta la casistica del passaggio
all'indietro di tutti gli errori rilevabili dalle funzioni usate nelle fasi
successive.  Questo comporterebbe una notevole complessità, mentre sarebbe
molto più comodo poter tornare direttamente al ciclo di lettura principale,
scartando l'input come errato.\footnote{a meno che, come precisa \cite{glibc},
  alla chiusura di ciascuna fase non siano associate operazioni di pulizia
  specifiche (come deallocazioni, chiusure di file, ecc.), che non potrebbero
  essere eseguite con un salto non-locale.}

Tutto ciò può essere realizzato proprio con un salto non-locale; questo di
norma viene realizzato salvando il contesto dello stack nel punto in cui si
vuole tornare in caso di errore, e ripristinandolo, in modo da tornare nella
funzione da cui si era partiti, quando serve.  La funzione che permette di
salvare il contesto dello stack è \funcd{setjmp}, il cui prototipo è:
\begin{functions}
  \headdecl{setjmp.h}
  \funcdecl{int setjmp(jmp\_buf env)}
  
  Salva il contesto dello stack. 

  \bodydesc{La funzione ritorna zero quando è chiamata direttamente e un
    valore diverso da zero quando ritorna da una chiamata di \func{longjmp}
    che usa il contesto salvato in precedenza.}
\end{functions}
  
Quando si esegue la funzione il contesto corrente dello stack viene salvato
nell'argomento \param{env}, una variabile di tipo
\type{jmp\_buf}\footnote{questo è un classico esempio di variabile di
  \textsl{tipo opaco}\index{tipo!opaco}. Si definiscono così strutture ed
  altri oggetti usati da una libreria, la cui struttura interna non deve
  essere vista dal programma chiamante (da cui il nome) che li devono
  utilizzare solo attraverso dalle opportune funzioni di gestione.}  che deve
essere stata definita in precedenza. In genere le variabili di tipo
\type{jmp\_buf} vengono definite come variabili globali in modo da poter
essere viste in tutte le funzioni del programma.

Quando viene eseguita direttamente la funzione ritorna sempre zero, un valore
diverso da zero viene restituito solo quando il ritorno è dovuto ad una
chiamata di \func{longjmp} in un'altra parte del programma che ripristina lo
stack effettuando il salto non-locale. Si tenga conto che il contesto salvato
in \param{env} viene invalidato se la routine che ha chiamato \func{setjmp}
ritorna, nel qual caso un successivo uso di \func{longjmp} può comportare
conseguenze imprevedibili (e di norma fatali) per il processo.
  
Come accennato per effettuare un salto non-locale ad
un punto precedentemente stabilito con \func{setjmp} si usa la funzione
\funcd{longjmp}; il suo prototipo è:
\begin{functions}
  \headdecl{setjmp.h}
  \funcdecl{void longjmp(jmp\_buf env, int val)}
  
  Ripristina il contesto dello stack.
  
  \bodydesc{La funzione non ritorna.}
\end{functions}

La funzione ripristina il contesto dello stack salvato da una chiamata a
\func{setjmp} nell'argomento \param{env}. Dopo l'esecuzione della funzione il
programma prosegue nel codice successivo al ritorno della \func{setjmp} con
cui si era salvato \param{env}, che restituirà il valore \param{val} invece di
zero.  Il valore di \param{val} specificato nella chiamata deve essere diverso
da zero, se si è specificato 0 sarà comunque restituito 1 al suo posto.

In sostanza un \func{longjmp} è analogo ad un \code{return}, solo che invece
di ritornare alla riga successiva della funzione chiamante, il programma
ritorna alla posizione della relativa \func{setjmp}, l'altra differenza è che
il ritorno può essere effettuato anche attraverso diversi livelli di funzioni
annidate.

L'implementazione di queste funzioni comporta alcune restrizioni dato che esse
interagiscono direttamente con la gestione dello stack ed il funzionamento del
compilatore stesso. In particolare \func{setjmp} è implementata con una macro,
pertanto non si può cercare di ottenerne l'indirizzo, ed inoltre delle
chiamate a questa funzione sono sicure solo in uno dei seguenti casi:
\begin{itemize}
\item come espressione di controllo in un comando condizionale, di selezione
  o di iterazione (come \code{if}, \code{switch} o \code{while});
\item come operando per un operatore di uguaglianza o confronto in una
  espressione di controllo di un comando condizionale, di selezione o di
  iterazione;
\item come operando per l'operatore di negazione (\code{!}) in una espressione
  di controllo di un comando condizionale, di selezione o di iterazione.
\item come espressione a sé stante.
\end{itemize}

In generale, dato che l'unica differenza fra la chiamata diretta e quella
ottenuta da un \func{longjmp}, è il valore di ritorno di \func{setjmp}, essa è
usualmente chiamata all'interno di un comando \code{if}. 

Uno dei punti critici dei salti non-locali è quello del valore delle
variabili, ed in particolare quello delle variabili automatiche della funzione
a cui si ritorna. In generale le variabili globali e statiche mantengono i
valori che avevano al momento della chiamata di \func{longjmp}, ma quelli
delle variabili automatiche (o di quelle dichiarate
\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 è
  originaria dell'epoca 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 è 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
\func{longjmp}, mentre quelli tenuti nei registri del processore (che nella
chiamata ad un'altra funzione 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
\direct{volatile}\footnote{la direttiva \direct{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).}.

\index{salto~non-locale|)}

%%% Local Variables: 
%%% mode: latex
%%% TeX-master: "gapil"
%%% End: 
