permessa: solo il proprietario del file o un processo con sufficienti
privilegi può eseguire l'operazione.
\item \errcode{ENOENT} \textit{No such file or directory}. Il file indicato
- dal \index{\textit{pathname}}\textit{pathname} non esiste: o una delle
+ dal \itindex{pathname}\textit{pathname} non esiste: o una delle
componenti non esiste o il \textit{pathname} contiene un link simbolico
spezzato. Errore tipico di un riferimento ad un file che si suppone
erroneamente essere esistente.
consentono l'operazione.
\item \errcode{ELOOP} \textit{Too many symbolic links encountered}. Ci sono
troppi link simbolici nella risoluzione di un
- \index{\textit{pathname}}\textit{pathname}.
+ \itindex{pathname}\textit{pathname}.
\item \errcode{ENAMETOOLONG} \textit{File name too long}. Si è indicato un
- \textit{pathname} troppo lungo.
+ \itindex{pathname}\textit{pathname} troppo lungo.
\item \errcode{ENOTBLK} \textit{Block device required}. Si è specificato un
file che non è un \textit{block device} in un contesto in cui era necessario
specificare un \textit{block device} (ad esempio si è tentato di montare un
\item \errcode{ENOMEM} \textit{No memory available}. Il kernel non è in grado
di allocare ulteriore memoria per completare l'operazione richiesta.
\item \errcode{EDEADLK} \textit{Deadlock avoided}. L'allocazione di una
- risorsa avrebbe causato un \textit{deadlock}\index{\textit{deadlock}}. Non
- sempre il sistema è in grado di riconoscere queste situazioni, nel qual caso
- si avrebbe il blocco.
+ risorsa avrebbe causato un \textit{deadlock}\itindex{deadlock}. Non sempre
+ il sistema è in grado di riconoscere queste situazioni, nel qual caso si
+ avrebbe il blocco.
\item \errcode{EFAULT} \textit{Bad address}. Una stringa passata come argomento
è fuori dello spazio di indirizzi del processo, in genere questa situazione
provoca l'emissione di un segnale di \textit{segment violation}
ritardata inutilmente nell'attesa del completamento di quella bloccata, mentre
nel peggiore dei casi (quando la conclusione della operazione bloccata dipende
da quanto si otterrebbe dal file descriptor ``\textsl{disponibile}'') si
-potrebbe addirittura arrivare ad un \textit{deadlock}\index{\textit{deadlock}}.
+potrebbe addirittura arrivare ad un \textit{deadlock}\itindex{deadlock}.
Abbiamo già accennato in sez.~\ref{sec:file_open} che è possibile prevenire
questo tipo di comportamento delle funzioni di I/O aprendo un file in
restituendo l'errore \errcode{EAGAIN}. L'utilizzo di questa modalità di I/O
permette di risolvere il problema controllando a turno i vari file descriptor,
in un ciclo in cui si ripete l'accesso fintanto che esso non viene garantito.
-Ovviamente questa tecnica, detta \textit{polling}\index{\textit{polling}}, è
+Ovviamente questa tecnica, detta \textit{polling}\itindex{polling}, è
estremamente inefficiente: si tiene costantemente impiegata la CPU solo per
eseguire in continuazione delle system call che nella gran parte dei casi
falliranno.
\param{exceptfds}), non diventa attivo, per un tempo massimo specificato da
\param{timeout}.
-\index{\textit{file~descriptor~set}|(}
+\itindbeg{file~descriptor~set}
+
Per specificare quali file descriptor si intende \textsl{selezionare}, la
funzione usa un particolare oggetto, il \textit{file descriptor set},
identificato dal tipo \type{fd\_set}, che serve ad identificare un insieme di
file descriptor, in maniera analoga a come un
-\index{\textit{signal~set}}\textit{signal set} (vedi
-sez.~\ref{sec:sig_sigset}) identifica un insieme di segnali. Per la
-manipolazione di questi \textit{file descriptor set} si possono usare delle
-opportune macro di preprocessore:
+\itindex{signal~set}\textit{signal set} (vedi sez.~\ref{sec:sig_sigset})
+identifica un insieme di segnali. Per la manipolazione di questi \textit{file
+ descriptor set} si possono usare delle opportune macro di preprocessore:
\begin{functions}
\headdecl{sys/time.h}
\headdecl{sys/types.h}
specificare anche un tempo nullo (cioè una struttura \struct{timeval} con i
campi impostati a zero), qualora si voglia semplicemente controllare lo stato
corrente dei file descriptor.
-\index{\textit{file~descriptor~set}|)}
+\itindend{file~descriptor~set}
La funzione restituisce il numero di file descriptor pronti,\footnote{questo è
il comportamento previsto dallo standard, ma la standardizzazione della
funzione.
L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
-race condition\index{\textit{race~condition}} quando ci si deve porre in
+\textit{race condition}\itindex{race~condition} quando ci si deve porre in
attesa sia di un segnale che di dati. La tecnica classica è quella di
utilizzare il gestore per impostare una variabile globale e controllare questa
nel corpo principale del programma; abbiamo visto in
può fare conto sul fatto che all'arrivo di un segnale essa verrebbe interrotta
e si potrebbero eseguire di conseguenza le operazioni relative al segnale e
alla gestione dati con un ciclo del tipo:
-\includecodesnip{listati/select_race.c} qui però emerge una race
-condition,\index{\textit{race~condition}} perché se il segnale arriva prima
-della chiamata a \func{select}, questa non verrà interrotta, e la ricezione
-del segnale non sarà rilevata.
+\includecodesnip{listati/select_race.c} qui però emerge una \textit{race
+ condition},\itindex{race~condition} perché se il segnale arriva prima della
+chiamata a \func{select}, questa non verrà interrotta, e la ricezione del
+segnale non sarà rilevata.
Per questo è stata introdotta \func{pselect} che attraverso l'argomento
\param{sigmask} permette di riabilitare la ricezione il segnale
contestualmente all'esecuzione della funzione,\footnote{in Linux però non è
presente la relativa system call, e la funzione è implementata nelle
\acr{glibc} attraverso \func{select} (vedi \texttt{man select\_tut}) per cui
- la possibilità di race condition permane; esiste però una soluzione,
- chiamata \index{\textit{self-pipe trick}}\textit{self-pipe trick}, che
- consiste nell'aprire una pipe (vedi sez.~\ref{sec:ipc_pipes}) ed usare
- \func{select} sul capo in lettura della stessa, e indicare l'arrivo di un
- segnale scrivendo sul capo in scrittura all'interno del manipolatore; in
- questo modo anche se il segnale va perso prima della chiamata di
- \func{select} questa lo riconoscerà comunque dalla presenza di dati sulla
- pipe.} ribloccandolo non appena essa ritorna, così che il precedente codice
-potrebbe essere riscritto nel seguente modo:
-\includecodesnip{listati/pselect_norace.c} in questo caso utilizzando
-\var{oldmask} durante l'esecuzione di \func{pselect} la ricezione del segnale
-sarà abilitata, ed in caso di interruzione si potranno eseguire le relative
-operazioni.
+ la possibilità di \itindex{race~condition}\textit{race condition} permane;
+ esiste però una soluzione, chiamata \itindex{self-pipe trick}
+ \textit{self-pipe trick}, che consiste nell'aprire una pipe (vedi
+ sez.~\ref{sec:ipc_pipes}) ed usare \func{select} sul capo in lettura della
+ stessa, e indicare l'arrivo di un segnale scrivendo sul capo in scrittura
+ all'interno del manipolatore; in questo modo anche se il segnale va perso
+ prima della chiamata di \func{select} questa lo riconoscerà comunque dalla
+ presenza di dati sulla pipe.} ribloccandolo non appena essa ritorna, così
+che il precedente codice potrebbe essere riscritto nel seguente modo:
+\includecodesnip{listati/pselect_norace.c}
+in questo caso utilizzando \var{oldmask} durante l'esecuzione di
+\func{pselect} la ricezione del segnale sarà abilitata, ed in caso di
+interruzione si potranno eseguire le relative operazioni.
\subsection{File mappati in memoria}
\label{sec:file_memory_map}
+\itindbeg{memory~mapping}
Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
rispetto a quella classica vista in cap.~\ref{cha:file_unix_interface}, è il
cosiddetto \textit{memory-mapped I/O}, che, attraverso il meccanismo della
\label{fig:file_mmap_layout}
\end{figure}
-L'uso del \textit{memory-mappung} comporta una notevole semplificazione delle
+L'uso del \textit{memory-mapping} comporta una notevole semplificazione delle
operazioni di I/O, in quanto non sarà più necessario utilizzare dei buffer
intermedi su cui appoggiare i dati da traferire, poiché questi potranno essere
acceduti direttamente nella sezione di memoria mappata; inoltre questa
privata cui solo il processo chiamante ha
accesso. Le modifiche sono mantenute attraverso
il meccanismo del \textit{copy on
- write}\index{\textit{copy~on~write}} e
+ write}\itindex{copy~on~write} e
salvate su swap in caso di necessità. Non è
specificato se i cambiamenti sul file originale
vengano riportati sulla regione
\const{MAP\_EXECUTABLE}& Ignorato. \\
\const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
delle pagine di swap ad uso del meccanismo del
- \textit{copy on
- write}\index{\textit{copy~on~write}}
+ \textit{copy on write}\itindex{copy~on~write}
per mantenere le
modifiche fatte alla regione mappata, in
questo caso dopo una scrittura, se non c'è più
Alla conclusione del processo, ogni pagina mappata verrà automaticamente
rilasciata, mentre la chiusura del file descriptor usato per effettuare la
mappatura in memoria non ha alcun effetto sulla stessa.
+\itindend{memory~mapping}
\section{Il file locking}
in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
stesso file non è possibile determinare la sequenza in cui essi opereranno.
-Questo causa la possibilità di race condition\index{\textit{race~condition}};
-in generale le situazioni più comuni sono due: l'interazione fra un processo
-che scrive e altri che leggono, in cui questi ultimi possono leggere
-informazioni scritte solo in maniera parziale o incompleta; o quella in cui
-diversi processi scrivono, mescolando in maniera imprevedibile il loro output
-sul file.
+Questo causa la possibilità di una \textit{race condition}
+\itindex{race~condition}; in generale le situazioni più comuni sono due:
+l'interazione fra un processo che scrive e altri che leggono, in cui questi
+ultimi possono leggere informazioni scritte solo in maniera parziale o
+incompleta; o quella in cui diversi processi scrivono, mescolando in maniera
+imprevedibile il loro output sul file.
In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le race condition\index{\textit{race~condition}}, attraverso una serie
-di funzioni che permettono di bloccare l'accesso al file da parte di altri
-processi, così da evitare le sovrapposizioni, e garantire la atomicità delle
-operazioni di scrittura.
+evitare le \textit{race condition}\itindex{race~condition}, attraverso una
+serie di funzioni che permettono di bloccare l'accesso al file da parte di
+altri processi, così da evitare le sovrapposizioni, e garantire la atomicità
+delle operazioni di scrittura.
perciò le informazioni relative agli eventuali \textit{file lock} sono
mantenute a livello di inode\index{inode},\footnote{in particolare, come
accennato in fig.~\ref{fig:file_flock_struct}, i \textit{file lock} sono
- mantenuti un una \textit{linked~list}\index{\textit{linked list}} di
- strutture \struct{file\_lock}. La lista è referenziata dall'indirizzo di
- partenza mantenuto dal campo \var{i\_flock} della struttura \struct{inode}
- (per le definizioni esatte si faccia riferimento al file \file{fs.h} nei
- sorgenti del kernel). Un bit del campo \var{fl\_flags} di specifica se si
- tratta di un lock in semantica BSD (\const{FL\_FLOCK}) o POSIX
- (\const{FL\_POSIX}).} dato che questo è l'unico riferimento in comune che
-possono avere due processi diversi che aprono lo stesso file.
+ mantenuti un una \textit{linked~list} di strutture \struct{file\_lock}. La
+ lista è referenziata dall'indirizzo di partenza mantenuto dal campo
+ \var{i\_flock} della struttura \struct{inode} (per le definizioni esatte si
+ faccia riferimento al file \file{fs.h} nei sorgenti del kernel). Un bit del
+ campo \var{fl\_flags} di specifica se si tratta di un lock in semantica BSD
+ (\const{FL\_FLOCK}) o POSIX (\const{FL\_POSIX}).} \itindex{linked~list} dato
+che questo è l'unico riferimento in comune che possono avere due processi
+diversi che aprono lo stesso file.
\begin{figure}[htb]
\centering
\item[\errcode{EDEADLK}] Si è richiesto un lock su una regione bloccata da
un altro processo che è a sua volta in attesa dello sblocco di un lock
mantenuto dal processo corrente; si avrebbe pertanto un
- \textit{deadlock}\index{\textit{deadlock}}. Non è garantito che il
- sistema riconosca sempre questa situazione.
+ \textit{deadlock}\itindex{deadlock}. Non è garantito che il sistema
+ riconosca sempre questa situazione.
\item[\errcode{EINTR}] La funzione è stata interrotta da un segnale prima
di poter acquisire un lock.
\end{errlist}
\begin{figure}[htb]
\centering \includegraphics[width=9cm]{img/file_lock_dead}
- \caption{Schema di una situazione di
- \textit{deadlock}\index{\textit{deadlock}}.}
+ \caption{Schema di una situazione di \textit{deadlock}\itindex{deadlock}.}
\label{fig:file_flock_dead}
\end{figure}
del processo 2; il processo 1 si bloccherà fintanto che il processo 2 non
rilasci il blocco. Ma cosa accade se il processo 2 nel frattempo tenta a sua
volta di ottenere un lock sulla regione A? Questa è una tipica situazione che
-porta ad un \textit{deadlock}\index{\textit{deadlock}}, dato che a quel punto
-anche il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro
-processo. Per questo motivo il kernel si incarica di rilevare situazioni di
-questo tipo, ed impedirle restituendo un errore di \errcode{EDEADLK} alla
-funzione che cerca di acquisire un lock che porterebbe ad un
-\textit{deadlock}.
+porta ad un \textit{deadlock}\itindex{deadlock}, dato che a quel punto anche
+il processo 2 si bloccherebbe, e niente potrebbe sbloccare l'altro processo.
+Per questo motivo il kernel si incarica di rilevare situazioni di questo tipo,
+ed impedirle restituendo un errore di \errcode{EDEADLK} alla funzione che
+cerca di acquisire un lock che porterebbe ad un \textit{deadlock}.
\begin{figure}[!bht]
\centering \includegraphics[width=13cm]{img/file_posix_lock}
Quando si richiede un lock il kernel effettua una scansione di tutti i lock
presenti sul file\footnote{scandisce cioè la
- \index{\textit{linked~list}}\textit{linked list} delle strutture
+ \itindex{linked~list}\textit{linked list} delle strutture
\struct{file\_lock}, scartando automaticamente quelle per cui
\var{fl\_flags} non è \const{FL\_POSIX}, così che le due interfacce restano
ben separate.} per verificare se la regione richiesta non si sovrappone ad
\errval{ENOSPC}, \errval{EIO}.}
\end{prototype}
-La funzione crea sul \index{\textit{pathname}}\textit{pathname}
-\param{newpath} un collegamento diretto al file indicato da \param{oldpath}.
-Per quanto detto la creazione di un nuovo collegamento diretto non copia il
-contenuto del file, ma si limita a creare una voce nella directory specificata
-da \param{newpath} e ad aumentare di uno il numero di riferimenti al file
-(riportato nel campo \var{st\_nlink} della struttura \struct{stat}, vedi
-sez.~\ref{sec:file_stat}) aggiungendo il nuovo nome ai precedenti. Si noti che
-uno stesso file può essere così chiamato con vari nomi in diverse directory.
+La funzione crea sul \itindex{pathname}\textit{pathname} \param{newpath} un
+collegamento diretto al file indicato da \param{oldpath}. Per quanto detto la
+creazione di un nuovo collegamento diretto non copia il contenuto del file, ma
+si limita a creare una voce nella directory specificata da \param{newpath} e
+ad aumentare di uno il numero di riferimenti al file (riportato nel campo
+\var{st\_nlink} della struttura \struct{stat}, vedi sez.~\ref{sec:file_stat})
+aggiungendo il nuovo nome ai precedenti. Si noti che uno stesso file può
+essere così chiamato con vari nomi in diverse directory.
Per quanto dicevamo in sez.~\ref{sec:file_filesystem} la creazione di un
collegamento diretto è possibile solo se entrambi i
-\index{\textit{pathname}}\textit{pathname} sono nello stesso filesystem;
-inoltre il filesystem deve supportare i collegamenti diretti (il meccanismo
-non è disponibile ad esempio con il filesystem \acr{vfat} di Windows).
+\itindex{pathname}\textit{pathname} sono nello stesso filesystem; inoltre il
+filesystem deve supportare i collegamenti diretti (il meccanismo non è
+disponibile ad esempio con il filesystem \acr{vfat} di Windows).
La funzione inoltre opera sia sui file ordinari che sugli altri oggetti del
filesystem, con l'eccezione delle directory. In alcune versioni di Unix solo
\param{oldpath} o più in generale si è cercato di creare una directory come
sotto-directory di se stessa.
\item[\errcode{ENOTDIR}] Uno dei componenti dei
- \index{\textit{pathname}}\textit{pathname} non è una directory o
- \param{oldpath} è una directory e \param{newpath} esiste e non è una
- directory.
+ \itindex{pathname}\textit{pathname} non è una directory o \param{oldpath}
+ è una directory e \param{newpath} esiste e non è una directory.
\end{errlist}
ed inoltre \errval{EACCES}, \errval{EPERM}, \errval{EMLINK},
\errval{ENOENT}, \errval{ENOMEM}, \errval{EROFS}, \errval{ELOOP} e
\file{/boot/boot/boot} e così via.
Per questo motivo il kernel e le librerie prevedono che nella risoluzione di
-un \index{\textit{pathname}}\textit{pathname} possano essere seguiti un numero
+un \itindex{pathname}\textit{pathname} possano essere seguiti un numero
limitato di link simbolici, il cui valore limite è specificato dalla costante
\const{MAXSYMLINKS}. Qualora questo limite venga superato viene generato un
errore ed \var{errno} viene impostata al valore \errcode{ELOOP}.
La funzione crea una nuova directory vuota, che contiene cioè solo le due voci
standard (\file{.} e \file{..}), con il nome indicato dall'argomento
\param{dirname}. Il nome può essere indicato sia come
-\index{\textit{pathname}}\textit{pathname} assoluto che relativo.
+\itindex{pathname}\textit{pathname} assoluto che relativo.
I permessi di accesso alla directory (vedi sez.~\ref{sec:file_access_control})
sono specificati da \param{mode}, i cui possibili valori sono riportati in
La funzione cancella la directory \param{dirname}, che deve essere vuota (la
directory deve cioè contenere soltanto le due voci standard \file{.} e
\file{..}). Il nome può essere indicato con il
-\index{\textit{pathname}}\textit{pathname} assoluto o relativo.
+\itindex{pathname}\textit{pathname} assoluto o relativo.
La modalità con cui avviene la cancellazione è analoga a quella di
\func{unlink}: fintanto che il numero di link all'inode\index{inode} della
\end{functions}
La funzione restituisce in \param{result} (come
-\index{\textit{value~result~argument}}\textit{value result argument})
-l'indirizzo dove sono stati salvati i dati, che di norma corrisponde a quello
-della struttura precedentemente allocata e specificata dall'argomento
-\param{entry} (anche se non è assicurato che la funzione usi lo spazio fornito
-dall'utente).
+\itindex{value~result~argument}\textit{value result argument}) l'indirizzo
+dove sono stati salvati i dati, che di norma corrisponde a quello della
+struttura precedentemente allocata e specificata dall'argomento \param{entry}
+(anche se non è assicurato che la funzione usi lo spazio fornito dall'utente).
I vari campi di \struct{dirent} contengono le informazioni relative alle voci
presenti nella directory; sia BSD che SVr4\footnote{POSIX prevede invece solo
\subsection{La directory di lavoro}
\label{sec:file_work_dir}
+\itindbeg{pathname}
+
A ciascun processo è associata una directory nel filesystem che è chiamata
\textsl{directory corrente} o \textsl{directory di lavoro} (in inglese
\textit{current working directory}) che è quella a cui si fa riferimento
-quando un \index{\textit{pathname}}\textit{pathname} è espresso in forma
+quando un \itindsub{pathname}{relativo}\textit{pathname} è espresso in forma
relativa, dove il ``\textsl{relativa}'' fa riferimento appunto a questa
directory.
directory corrente di qualunque comando da essa lanciato.
In genere il kernel tiene traccia per ciascun processo dell'inode\index{inode}
-della directory di lavoro, per ottenere il
-\index{\textit{pathname}}\textit{pathname} occorre usare una apposita funzione
-di libreria, \funcd{getcwd}, il cui prototipo è:
+della directory di lavoro, per ottenere il \textit{pathname}
+occorre usare una apposita funzione di libreria, \funcd{getcwd}, il cui
+prototipo è:
\begin{prototype}{unistd.h}{char *getcwd(char *buffer, size\_t size)}
Legge il \textit{pathname} della directory di lavoro corrente.
\end{errlist}}
\end{prototype}
-La funzione restituisce il \index{\textit{pathname}}\textit{pathname} completo
-della directory di lavoro nella stringa puntata da \param{buffer}, che deve
-essere precedentemente allocata, per una dimensione massima di \param{size}.
-Il buffer deve essere sufficientemente lungo da poter contenere il
+La funzione restituisce il \textit{pathname} completo della directory di
+lavoro nella stringa puntata da \param{buffer}, che deve essere
+precedentemente allocata, per una dimensione massima di \param{size}. Il
+buffer deve essere sufficientemente lungo da poter contenere il
\textit{pathname} completo più lo zero di terminazione della stringa. Qualora
esso ecceda le dimensioni specificate con \param{size} la funzione restituisce
un errore.
\param{buffer},\footnote{questa è un'estensione allo standard POSIX.1,
supportata da Linux.} nel qual caso la stringa sarà allocata automaticamente
per una dimensione pari a \param{size} qualora questa sia diversa da zero, o
-della lunghezza esatta del \index{\textit{pathname}}\textit{pathname}
-altrimenti. In questo caso ci si deve ricordare di disallocare la stringa una
-volta cessato il suo utilizzo.
+della lunghezza esatta del \textit{pathname} altrimenti. In questo caso ci si
+deve ricordare di disallocare la stringa una volta cessato il suo utilizzo.
Di questa funzione esiste una versione \code{char *getwd(char *buffer)} fatta
per compatibilità all'indietro con BSD, che non consente di specificare la
dimensione del buffer; esso deve essere allocato in precedenza ed avere una
dimensione superiore a \const{PATH\_MAX} (di solito 256 byte, vedi
sez.~\ref{sec:sys_limits}); il problema è che in Linux non esiste una
-dimensione superiore per un \index{\textit{pathname}}\textit{pathname}, per
-cui non è detto che il buffer sia sufficiente a contenere il nome del file, e
-questa è la ragione principale per cui questa funzione è deprecata.
+dimensione superiore per un \textit{pathname}, per cui non è detto che il
+buffer sia sufficiente a contenere il nome del file, e questa è la ragione
+principale per cui questa funzione è deprecata.
Una seconda funzione simile è \code{char *get\_current\_dir\_name(void)} che è
sostanzialmente equivalente ad una \code{getcwd(NULL, 0)}, con la sola
differenza che essa ritorna il valore della variabile di ambiente \val{PWD},
che essendo costruita dalla shell può contenere un \textit{pathname}
comprendente anche dei link simbolici. Usando \func{getcwd} infatti, essendo
-il \index{\textit{pathname}}\textit{pathname} ricavato risalendo all'indietro
-l'albero della directory, si perderebbe traccia di ogni passaggio attraverso
-eventuali link simbolici.
+il \textit{pathname} ricavato risalendo all'indietro l'albero della directory,
+si perderebbe traccia di ogni passaggio attraverso eventuali link simbolici.
Per cambiare la directory di lavoro si può usare la funzione \funcd{chdir}
(equivalente del comando di shell \cmd{cd}) il cui nome sta appunto per
quale si hanno i permessi di accesso.
Dato che anche le directory sono file, è possibile riferirsi ad esse anche
-tramite il file descriptor, e non solo tramite il
-\index{\textit{pathname}}\textit{pathname}, per fare questo si usa
-\funcd{fchdir}, il cui prototipo è:
+tramite il file descriptor, e non solo tramite il \textit{pathname}, per fare
+questo si usa \funcd{fchdir}, il cui prototipo è:
\begin{prototype}{unistd.h}{int fchdir(int fd)}
Identica a \func{chdir}, ma usa il file descriptor \param{fd} invece del
\textit{pathname}.
quello in cui il processo non ha il permesso di accesso alla directory
specificata da \param{fd}.
+\itindend{pathname}
+
\subsection{I file temporanei}
prima vista. Infatti anche se sembrerebbe banale generare un nome a caso e
creare il file dopo aver controllato che questo non esista, nel momento fra il
controllo e la creazione si ha giusto lo spazio per una possibile \textit{race
- condition}\index{\textit{race~condition}} (si ricordi quanto visto in
+ condition}\itindex{race~condition} (si ricordi quanto visto in
sez.~\ref{sec:proc_race_cond}).
Le \acr{glibc} provvedono varie funzioni per generare nomi di file temporanei,
standard non specifica in quale directory verrà aperto il file, ma le
\acr{glibc} prima tentano con \const{P\_tmpdir} e poi con \file{/tmp}. Questa
funzione è rientrante e non soffre di problemi di \textit{race
- condition}\index{\textit{race~condition}}.
+ condition}\itindex{race~condition}.
Alcune versioni meno recenti di Unix non supportano queste funzioni; in questo
caso si possono usare le vecchie funzioni \funcd{mktemp} e \func{mkstemp} che
\end{prototype}
\noindent dato che \param{template} deve poter essere modificata dalla
funzione non si può usare una stringa costante. Tutte le avvertenze riguardo
-alle possibili \textit{race condition}\index{\textit{race~condition}} date per
+alle possibili \textit{race condition}\itindex{race~condition} date per
\func{tmpnam} continuano a valere; inoltre in alcune vecchie implementazioni
il valore usato per sostituire le \code{XXXXXX} viene formato con il \acr{pid}
del processo più una lettera, il che mette a disposizione solo 26 possibilità
\noindent la directory è creata con permessi \code{0700} (al solito si veda
cap.~\ref{cha:file_unix_interface} per i dettagli); dato che la creazione
della directory è sempre esclusiva i precedenti problemi di \textit{race
- condition}\index{\textit{race~condition}} non si pongono.
+ condition}\itindex{race~condition} non si pongono.
\section{La manipolazione delle caratteristiche dei files}
Il campo \var{st\_size} contiene la dimensione del file in byte (se si tratta
di un file regolare, nel caso di un link simbolico la dimensione è quella del
-\index{\textit{pathname}}\textit{pathname} che contiene, per le fifo è sempre
-nullo).
+\itindex{pathname}\textit{pathname} che contiene, per le fifo è sempre nullo).
Il campo \var{st\_blocks} definisce la lunghezza del file in blocchi di 512
byte. Il campo \var{st\_blksize} infine definisce la dimensione preferita per
\begin{errlist}
\item[\errcode{EACCES}] il file non ha permesso di scrittura o non si ha il
permesso di esecuzione una delle directory del
- \index{\textit{pathname}}\textit{pathname}.
+ \itindex{pathname}\textit{pathname}.
\item[\errcode{ETXTBSY}] Il file è un programma in esecuzione.
\end{errlist}
ed anche \errval{ENOTDIR}, \errval{ENAMETOOLONG}, \errval{ENOENT},
avanti.
La prima regola è che per poter accedere ad un file attraverso il suo
-\textit{pathname} occorre il permesso di esecuzione in ciascuna delle
-directory che compongono il \textit{pathname}; lo stesso vale per aprire un
-file nella directory corrente (per la quale appunto serve il diritto di
-esecuzione).
+\itindex{pathname}\textit{pathname} occorre il permesso di esecuzione in
+ciascuna delle directory che compongono il \textit{pathname}; lo stesso vale
+per aprire un file nella directory corrente (per la quale appunto serve il
+diritto di esecuzione).
Per una directory infatti il permesso di esecuzione significa che essa può
-essere attraversata nella risoluzione del
-\index{\textit{pathname}}\textit{pathname}, ed è distinto dal permesso di
-lettura che invece implica che si può leggere il contenuto della directory.
+essere attraversata nella risoluzione del \itindex{pathname}\textit{pathname},
+ed è distinto dal permesso di lettura che invece implica che si può leggere il
+contenuto della directory.
Questo significa che se si ha il permesso di esecuzione senza permesso di
lettura si potrà lo stesso aprire un file in una directory (se si hanno i
di norma corrispondente alla radice dell'albero di file e directory come visto
dal kernel (ed illustrato in sez.~\ref{sec:file_organization}), ha per il
processo il significato specifico di directory rispetto alla quale vengono
-risolti i \index{\textit{pathname}!assoluto}\textit{pathname}
+risolti i \itindsub{pathname}{assoluto}\textit{pathname}
assoluti.\footnote{cioè quando un processo chiede la risoluzione di un
\textit{pathname}, il kernel usa sempre questa directory come punto di
partenza.} Il fatto che questo valore sia specificato per ogni processo apre
allora la possibilità di modificare le modalità di risoluzione dei
\textit{pathname} assoluti da parte di un processo cambiando questa directory,
-così come si fa coi \index{\textit{pathname}!relativo}\textit{pathname}
-relativi cambiando la directory di lavoro.
+così come si fa coi \itindsub{pathname}{relativo}\textit{pathname} relativi
+cambiando la directory di lavoro.
Normalmente la directory radice di un processo coincide anche con la radice
del filesystem usata dal kernel, e dato che il suo valore viene ereditato dal
padre da ogni processo figlio, in generale i processi risolvono i
-\index{\textit{pathname}!assoluto}\textit{pathname} assoluti a partire sempre
-dalla stessa directory, che corrisponde alla \file{/} del sistema.
+\itindsub{pathname}{assoluto}\textit{pathname} assoluti a partire sempre dalla
+stessa directory, che corrisponde alla \file{/} del sistema.
In certe situazioni però, per motivi di sicurezza, è utile poter impedire che
un processo possa accedere a tutto il filesystem; per far questo si può
\end{prototype}
\noindent in questo modo la directory radice del processo diventerà
\param{path} (che ovviamente deve esistere) ed ogni
-\index{\textit{pathname}!assoluto}\textit{pathname} assoluto usato dalle
-funzioni chiamate nel processo sarà risolto a partire da essa, rendendo
-impossibile accedere alla parte di albero sovrastante. Si ha così quella che
-viene chiamata una \textit{chroot jail}, in quanto il processo non può più
-accedere a file al di fuori della sezione di albero in cui è stato
+\itindsub{pathname}{assoluto}\textit{pathname} assoluto usato dalle funzioni
+chiamate nel processo sarà risolto a partire da essa, rendendo impossibile
+accedere alla parte di albero sovrastante. Si ha così quella che viene
+chiamata una \textit{chroot jail}, in quanto il processo non può più accedere
+a file al di fuori della sezione di albero in cui è stato
\textsl{imprigionato}.
Solo un processo con i privilegi di amministratore può usare questa funzione,
si cedono i privilegi di root. Infatti se per un qualche motivo il processo
resta con la directory di lavoro fuori dalla \textit{chroot jail}, potrà
comunque accedere a tutto il resto del filesystem usando
-\index{\textit{pathname}!relativo}\textit{pathname} relativi, i quali,
-partendo dalla directory di lavoro che è fuori della \textit{chroot jail},
-potranno (con l'uso di \texttt{..}) risalire fino alla radice effettiva del
-filesystem.
+\itindsub{pathname}{relativo}\textit{pathname} relativi, i quali, partendo
+dalla directory di lavoro che è fuori della \textit{chroot jail}, potranno
+(con l'uso di \texttt{..}) risalire fino alla radice effettiva del filesystem.
Ma se ad un processo restano i privilegi di amministratore esso potrà comunque
portare la sua directory di lavoro fuori dalla \textit{chroot jail} in cui si
\subsection{L'organizzazione di file e directory}
\label{sec:file_organization}
-\index{\textit{pathname}|(}
+\itindbeg{pathname}
In Unix, a differenza di quanto avviene in altri sistemi operativi, tutti i
file vengono tenuti all'interno di un unico albero la cui radice (quella che
viene chiamata \textit{root directory}) viene montata all'avvio. Un file
directory radice del processo; questa, a meno di un \func{chroot} (su cui
torneremo in sez.~\ref{sec:file_chroot}) è la stessa per tutti i processi ed
equivale alla directory radice dell'albero dei file: in questo caso si parla
-di un \textsl{pathname assoluto}\index{\textit{pathname}!assoluto}. Altrimenti
-la ricerca parte dalla directory corrente (su cui torneremo in
+di un \textsl{pathname assoluto} \itindsub{pathname}{assoluto}. Altrimenti la
+ricerca parte dalla directory corrente (su cui torneremo in
sez.~\ref{sec:file_work_dir}) ed il pathname è detto \textsl{pathname
-relativo}\index{\textit{pathname}!relativo}.
+ relativo} \itindsub{pathname}{relativo}.
I nomi \file{.} e \file{..} hanno un significato speciale e vengono inseriti
in ogni directory: il primo fa riferimento alla directory corrente e il
la directory che contiene il riferimento alla directory corrente; nel caso la
directory corrente coincida con la directory radice, allora il riferimento è a
se stessa.
+\itindend{pathname}
\subsection{I tipi di file}
sono implementati come oggetti del \textit{Virtual File System} (vedi
sez.~\ref{sec:file_vfs_work}) e sono presenti in tutti i filesystem unix-like
utilizzabili con Linux. L'elenco dei vari tipi di file definiti dal
-\textit{Virtual File System}\index{\textit{Virtual~File~System}} è riportato in
+\textit{Virtual File System}\itindex{Virtual~File~System} è riportato in
tab.~\ref{tab:file_file_types}.
Si tenga ben presente che questa classificazione non ha nulla a che fare con
% introdotti qui alcuni termini che potranno comparire in seguito, come
% \textit{inode}, \textit{dentry}, \textit{dcache}.
+\itindbeg{Virtual~File~System}
In Linux il concetto di \textit{everything is a file} è stato implementato
-attraverso il \textit{Virtual File System}\index{\textit{Virtual~File~System}}
-(da qui in avanti VFS) che è uno strato intermedio che il kernel usa per
-accedere ai più svariati filesystem mantenendo la stessa interfaccia per i
-programmi in user space. Esso fornisce un livello di indirezione che permette
-di collegare le operazioni di manipolazione sui file alle operazioni di I/O, e
-gestisce l'organizzazione di queste ultime nei vari modi in cui i diversi
-filesystem le effettuano, permettendo la coesistenza di filesystem differenti
-all'interno dello stesso albero delle directory.
+attraverso il \textit{Virtual File System} (da qui in avanti VFS) che è uno
+strato intermedio che il kernel usa per accedere ai più svariati filesystem
+mantenendo la stessa interfaccia per i programmi in user space. Esso fornisce
+un livello di indirezione che permette di collegare le operazioni di
+manipolazione sui file alle operazioni di I/O, e gestisce l'organizzazione di
+queste ultime nei vari modi in cui i diversi filesystem le effettuano,
+permettendo la coesistenza di filesystem differenti all'interno dello stesso
+albero delle directory.
Quando un processo esegue una system call che opera su un file, il kernel
chiama sempre una funzione implementata nel VFS; la funzione eseguirà le
\subsection{Il funzionamento del \textit{Virtual File System}}
\label{sec:file_vfs_work}
-La funzione più importante implementata dal
-VFS\index{\textit{Virtual~File~System}} è la system call \func{open} che
-permette di aprire un file. Dato un \index{\textit{pathname}}\textit{pathname}
+La funzione più importante implementata dal VFS è la system call \func{open}
+che permette di aprire un file. Dato un \itindex{pathname}\textit{pathname}
viene eseguita una ricerca dentro la \textit{directory entry cache} (in breve
\textit{dcache}), una tabella che contiene tutte le \textit{directory entry}
(in breve \textit{dentry}) che permette di associare in maniera rapida ed
l'albero dei file, ovviamente per non riempire tutta la memoria questa vista è
parziale (la \textit{dcache} cioè contiene solo le \textit{dentry} per i file
per i quali è stato richiesto l'accesso), quando si vuole risolvere un nuovo
-\index{\textit{pathname}}\textit{pathname} il VFS deve creare una nuova
+\itindex{pathname}\textit{pathname} il VFS deve creare una nuova
\textit{dentry} e caricare l'inode\index{inode} corrispondente in memoria.
Questo procedimento viene eseguito dal metodo \code{lookup()}
esempio la \code{seek}) non saranno disponibili, però con questo sistema
l'utilizzo di diversi filesystem (come quelli usati da Windows o MacOs) è
immediato e (relativamente) trasparente per l'utente ed il programmatore.
+\itindend{Virtual~File~System}
\subsection{Il funzionamento di un filesystem Unix}
prestazioni dato che viene ridotta la distanza fra i dati e la tabella degli
inode\index{inode}.
-Le directory sono implementate come una linked list con voci di dimensione
-variabile. Ciascuna voce della lista contiene il numero di inode\index{inode},
-la sua lunghezza, il nome del file e la sua lunghezza, secondo lo schema in
-fig.~\ref{fig:file_ext2_dirs}; in questo modo è possibile implementare nomi
-per i file anche molto lunghi (fino a 1024 caratteri) senza sprecare spazio
-disco.
+Le directory sono implementate come una \itindex{linked~list}\textit{linked
+ list} con voci di dimensione variabile. Ciascuna voce della lista contiene
+il numero di inode\index{inode}, la sua lunghezza, il nome del file e la sua
+lunghezza, secondo lo schema in fig.~\ref{fig:file_ext2_dirs}; in questo modo
+è possibile implementare nomi per i file anche molto lunghi (fino a 1024
+caratteri) senza sprecare spazio disco.
L'uso di \func{gets} è deprecato e deve essere assolutamente evitato; la
funzione infatti non controlla il numero di byte letti, per cui nel caso la
stringa letta superi le dimensioni del buffer, si avrà un \textit{buffer
- overflow}\index{\textit{buffer~overflow}}, con sovrascrittura della memoria
-del processo adiacente al buffer.\footnote{questa tecnica è spiegata in
- dettaglio e con molta efficacia nell'ormai famoso articolo di Aleph1
- \cite{StS}.}
+ overflow}\itindex{buffer~overflow}, con sovrascrittura della memoria del
+processo adiacente al buffer.\footnote{questa tecnica è spiegata in dettaglio
+ e con molta efficacia nell'ormai famoso articolo di Aleph1 \cite{StS}.}
Questa è una delle vulnerabilità più sfruttate per guadagnare accessi
non autorizzati al sistema (i cosiddetti \textit{exploit}), basta
subito, altrimenti il buffer viene allargato usando \func{realloc} e la nuova
dimensione ed il nuovo puntatore vengono passata indietro (si noti infatti
come per entrambi gli argomenti si siano usati dei
-\index{\textit{value~result~argument}}\textit{value result argument}, passando
-dei puntatori anziché i valori delle variabili, secondo la tecnica spiegata in
+\itindex{value~result~argument}\textit{value result argument}, passando dei
+puntatori anziché i valori delle variabili, secondo la tecnica spiegata in
sez.~\ref{sec:proc_var_passing}).
Se si passa alla funzione l'indirizzo di un puntatore impostato a \val{NULL} e
puntatore all'inizio del testo della linea letta. Un esempio di codice può
essere il seguente:
\includecodesnip{listati/getline.c}
-e per evitare memory leak\index{\textit{memory~leak}} occorre ricordarsi di
+e per evitare \textit{memory leak}\itindex{memory~leak} occorre ricordarsi di
liberare \var{ptr} con una \func{free}.
Il valore di ritorno della funzione indica il numero di caratteri letti
l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se non si ha la
sicurezza assoluta sulle dimensioni del risultato della stampa, eccedere le
dimensioni di \param{str}, con conseguente sovrascrittura di altre variabili e
-possibili \textit{buffer overflow}\index{\textit{buffer~overflow}}; per questo
-motivo si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo
-è:
+possibili \textit{buffer overflow}\itindex{buffer~overflow}; per questo motivo
+si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui prototipo è:
\begin{prototype}{stdio.h}
{snprintf(char *str, size\_t size, const char *format, ...)}
Identica a \func{sprintf}, ma non scrive su \param{str} più di
\param{size} caratteri.
\end{prototype}
\noindent in modo da evitare possibili buffer
-overflow\index{\textit{buffer~overflow}}.
+overflow\itindex{buffer~overflow}.
Per eliminare alla radice questi problemi, le \acr{glibc} supportano una
\bodydesc{Le funzioni ritornano il numero di caratteri stampati.}
\end{functions}
+
Entrambe le funzioni prendono come argomento \param{strptr} che deve essere
l'indirizzo di un puntatore ad una stringa di caratteri, in cui verrà
restituito (si ricordi quanto detto in sez.~\ref{sec:proc_var_passing} a
-proposito dei \index{\textit{value~result~argument}}\textit{value result
- argument}) l'indirizzo della stringa allocata automaticamente dalle
-funzioni. Occorre inoltre ricordarsi di invocare \func{free} per liberare
-detto puntatore quando la stringa non serve più, onde evitare memory
-leak\index{\textit{memory~leak}}.
+proposito dei \itindex{value~result~argument}\textit{value result argument})
+l'indirizzo della stringa allocata automaticamente dalle funzioni. Occorre
+inoltre ricordarsi di invocare \func{free} per liberare detto puntatore quando
+la stringa non serve più, onde evitare \textit{memory
+ leak}\itindex{memory~leak}.
Infine una ulteriore estensione GNU definisce le due funzioni \func{dprintf} e
\func{vdprintf}, che prendono un file descriptor al posto dello stream. Altre
\subsection{L'architettura dei \textit{file descriptor}}
\label{sec:file_fd}
-\index{file!descriptor|(} Per poter accedere al contenuto di un file occorre
+\index{file!descriptor|(}
+
+Per poter accedere al contenuto di un file occorre
creare un canale di comunicazione con il kernel che renda possibile operare su
di esso (si ricordi quanto visto in sez.~\ref{sec:file_vfs_work}). Questo si
fa aprendo il file con la funzione \func{open} che provvederà a localizzare
\label{sec:file_open}
La funzione \funcd{open} è la funzione fondamentale per accedere ai file, ed è
-quella che crea l'associazione fra un
-\index{\textit{pathname}}\textit{pathname} ed un file descriptor, il suo
-prototipo è:
+quella che crea l'associazione fra un \itindex{pathname}\textit{pathname} ed
+un file descriptor, il suo prototipo è:
\begin{functions}
\headdecl{sys/types.h}
\headdecl{sys/stat.h}
\footnotetext[2]{la pagina di manuale di \func{open} segnala che questa
opzione è difettosa su NFS, e che i programmi che la usano per stabilire un
- \textsl{file di lock}\index{file!di lock} possono incorrere in una race
- condition\index{\textit{race~condition}}. Si consiglia come alternativa di
- usare un file con un nome univoco e la funzione \func{link} per verificarne
- l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).}
+ \textsl{file di lock}\index{file!di lock} possono incorrere in una
+ \textit{race condition}\itindex{race~condition}. Si consiglia come
+ alternativa di usare un file con un nome univoco e la funzione \func{link}
+ per verificarne l'esistenza (vedi sez.~\ref{sec:ipc_file_lock}).}
\footnotetext[3]{\textit{Denial of Service}\index{DoS}, si chiamano così
attacchi miranti ad impedire un servizio causando una qualche forma di
la successiva scrittura avvenga alla fine del file, infatti se questo è stato
aperto anche da un altro processo che vi ha scritto, la fine del file può
essersi spostata, ma noi scriveremo alla posizione impostata in precedenza
-(questa è una potenziale sorgente di \textit{race condition}
-\index{\textit{race~condition}}, vedi sez.~\ref{sec:file_atomic}).
+(questa è una potenziale sorgente di \itindex{race~condition}\textit{race
+ condition}, vedi sez.~\ref{sec:file_atomic}).
Non tutti i file supportano la capacità di eseguire una \func{lseek}, in
questo caso la funzione ritorna l'errore \errcode{EPIPE}. Questo, oltre che per
Un caso tipico di necessità di accesso condiviso in scrittura è quello in cui
vari processi devono scrivere alla fine di un file (ad esempio un file di
log). Come accennato in sez.~\ref{sec:file_lseek} impostare la posizione alla
-fine del file e poi scrivere può condurre ad una \textit{race
- condition}\index{\textit{race~condition}}: infatti può succedere che un
+fine del file e poi scrivere può condurre ad una
+\itindex{race~condition}\textit{race condition}: infatti può succedere che un
secondo processo scriva alla fine del file fra la \func{lseek} e la
\func{write}; in questo caso, come abbiamo appena visto, il file sarà esteso,
ma il nostro primo processo avrà ancora la posizione corrente impostata con la
creare un \textsl{file di lock}\index{file!di lock}, bloccandosi se il file
esiste. In questo caso la sequenza logica porterebbe a verificare prima
l'esistenza del file con una \func{stat} per poi crearlo con una \func{creat};
-di nuovo avremmo la possibilità di una race
-condition\index{\textit{race~condition}} da parte di un altro processo che
-crea lo stesso file fra il controllo e la creazione.
+di nuovo avremmo la possibilità di una \textit{race
+ condition}\itindex{race~condition} da parte di un altro processo che crea lo
+stesso file fra il controllo e la creazione.
Per questo motivo sono stati introdotti per \func{open} i due flag
\const{O\_CREAT} e \const{O\_EXCL}. In questo modo l'operazione di controllo
della \textit{file table} a cui entrambi fanno riferimento). L'unica
differenza fra due file descriptor duplicati è che ciascuno avrà il suo
\textit{file descriptor flag}; a questo proposito va specificato che nel caso
-di \func{dup} il flag di \textit{close-on-exec}\index{\textit{close-on-exec}}
-(vedi sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre
-cancellato nella copia.
+di \func{dup} il flag di \textit{close-on-exec}\itindex{close-on-exec} (vedi
+sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl}) viene sempre cancellato
+nella copia.
L'uso principale di questa funzione è per la redirezione dell'input e
dell'output fra l'esecuzione di una \func{fork} e la successiva \func{exec};
massimo numero di descrittori consentito.
\item[\const{F\_SETFD}] imposta il valore del \textit{file descriptor flag} al
valore specificato con \param{arg}. Al momento l'unico bit usato è quello di
- \textit{close-on-exec}\index{\textit{close-on-exec}}, identificato dalla
- costante \const{FD\_CLOEXEC}, che serve a richiedere che il file venga
- chiuso nella esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}).
- Ritorna un valore nullo in caso di successo e -1 in caso di errore.
+ \textit{close-on-exec}\itindex{close-on-exec}, identificato dalla costante
+ \const{FD\_CLOEXEC}, che serve a richiedere che il file venga chiuso nella
+ esecuzione di una \func{exec} (vedi sez.~\ref{sec:proc_exec}). Ritorna un
+ valore nullo in caso di successo e -1 in caso di errore.
\item[\const{F\_GETFD}] ritorna il valore del \textit{file descriptor flag} di
\param{fd} o -1 in caso di errore; se \const{FD\_CLOEXEC} è impostato i file
descriptor aperti vengono chiusi attraverso una \func{exec} altrimenti (il
qui riportiamo solo i valori di alcuni comandi che sono definiti per ogni
file:
\begin{basedescript}{\desclabelwidth{2.0cm}}
-\item[\const{FIOCLEX}] Imposta il bit di \textit{close on exec}.
-\item[\const{FIONCLEX}] Cancella il bit di \textit{close on exec}.
+\item[\const{FIOCLEX}] Imposta il flag di
+ \textit{close-on-exec}\itindex{close-on-exec}.
+\item[\const{FIONCLEX}] Cancella il flag di
+ \textit{close-on-exec}\itindex{close-on-exec}.
\item[\const{FIOASYNC}] Abilita l'I/O asincrono.
\item[\const{FIONBIO}] Abilita l'I/O in modalità non bloccante.
\end{basedescript}
(e non possono accedere direttamente alle zone di memoria riservate o alle
porte di input/output).
-Una parte del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, si
-occupa di stabilire, ad intervalli fissi e sulla base di un opportuno calcolo
-delle priorità, quale ``\textsl{processo}'' deve essere posto in esecuzione
-(il cosiddetto \textit{preemptive
- scheduling}\index{\textit{preemptive~scheduling}}). Questo verrà comunque
+Una parte del kernel, lo \textit{scheduler}\itindex{scheduler}, si occupa di
+stabilire, ad intervalli fissi e sulla base di un opportuno calcolo delle
+priorità, quale ``\textsl{processo}'' deve essere posto in esecuzione (il
+cosiddetto \textit{prehemptive
+ multitasking}\itindex{prehemptive~multitasking}). Questo verrà comunque
eseguito in modalità protetta; quando necessario il processo potrà accedere
alle risorse hardware soltanto attraverso delle opportune chiamate al sistema
che restituiranno il controllo al kernel.
in sez.~\ref{sec:sys_user_group} queste informazioni possono essere
mantenute, con l'uso del \textit{Name Service Switch}, su varie tipologie di
supporti, compresi server centralizzati come LDAP.}
-\index{\textit{Name~Service~Switch}} Questi numeri sono l'\textit{user
- identifier}, detto in breve \textsl{user-ID}, ed indicato dall'acronimo
-\acr{uid}, e il \textit{group identifier}, detto in breve \textsl{group-ID},
-ed identificato dall'acronimo \acr{gid}, e sono quelli che vengono usati dal
-kernel per identificare l'utente.
+\itindex{Name~Service~Switch} Questi numeri sono l'\textit{user identifier},
+detto in breve \textsl{user-ID}, ed indicato dall'acronimo \acr{uid}, e il
+\textit{group identifier}, detto in breve \textsl{group-ID}, ed identificato
+dall'acronimo \acr{gid}, e sono quelli che vengono usati dal kernel per
+identificare l'utente.
In questo modo il sistema è in grado di tenere traccia dell'utente a cui
appartiene ciascun processo ed impedire ad altri utenti di interferire con
Si potrebbe obiettare che sarebbe molto più semplice salvare il risultato
intermedio su un file temporaneo. Questo però non tiene conto del fatto che un
\textit{CGI} deve poter gestire più richieste in concorrenza, e si avrebbe una
-evidente \textit{race condition}\index{\textit{race~condition}} in caso di
-accesso simultaneo a detto file.\footnote{il problema potrebbe essere superato
+evidente \textit{race condition}\itindex{race~condition} in caso di accesso
+simultaneo a detto file.\footnote{il problema potrebbe essere superato
determinando in anticipo un nome appropriato per il file temporaneo, che
verrebbe utilizzato dai vari sotto-processi, e cancellato alla fine della
loro esecuzione; ma a questo le cose non sarebbero più tanto semplici.}
lettura; è possibile anche usare la fifo all'interno di un solo processo, nel
qual caso però occorre stare molto attenti alla possibili situazioni di
stallo.\footnote{se si cerca di leggere da una fifo che non contiene dati si
- avrà un deadlock\index{\textit{deadlock}} immediato, dato che il processo si
- blocca e non potrà quindi mai eseguire le funzioni di scrittura.}
+ avrà un deadlock\itindex{deadlock} immediato, dato che il processo si blocca
+ e non potrà quindi mai eseguire le funzioni di scrittura.}
Per la loro caratteristica di essere accessibili attraverso il filesystem, è
piuttosto frequente l'utilizzo di una fifo come canale di comunicazione nelle
occorrerà definire la speciale variabile di ambiente \code{LD\_LIBRARY\_PATH}
in modo che il linker dinamico possa accedervi.
-In generale questa variabile indica il
-\index{\textit{pathname}}\textit{pathname} della directory contenente la
-libreria. Nell'ipotesi (che daremo sempre per verificata) che si facciano le
-prove direttamente nella directory dei sorgenti (dove di norma vengono creati
-sia i programmi che la libreria), il comando da dare sarà \code{export
- LD\_LIBRARY\_PATH=./}; a questo punto potremo lanciare il server, facendogli
-leggere una decina di frasi, con:
+In generale questa variabile indica il \itindex{pathname}\textit{pathname}
+della directory contenente la libreria. Nell'ipotesi (che daremo sempre per
+verificata) che si facciano le prove direttamente nella directory dei sorgenti
+(dove di norma vengono creati sia i programmi che la libreria), il comando da
+dare sarà \code{export LD\_LIBRARY\_PATH=./}; a questo punto potremo lanciare
+il server, facendogli leggere una decina di frasi, con:
\begin{verbatim}
[piccardi@gont sources]$ ./fortuned -n10
\end{verbatim}
\end{functions}
La funzione determina un valore della chiave sulla base di \param{pathname},
-che deve specificare il \index{\textit{pathname}}\textit{pathname} di un file
+che deve specificare il \itindex{pathname}\textit{pathname} di un file
effettivamente esistente e di un numero di progetto \param{proj\_id)}, che di
norma viene specificato come carattere, dato che ne vengono utilizzati solo
gli 8 bit meno significativi.\footnote{nelle libc4 e libc5, come avviene in
\end{figure}
-Una coda di messaggi è costituita da una
-\index{\textit{linked~list}}\textit{linked list};\footnote{una \textit{linked
- list} è una tipica struttura di dati, organizzati in una lista in cui
- ciascun elemento contiene un puntatore al successivo. In questo modo la
- struttura è veloce nell'estrazione ed immissione dei dati dalle estremità
- dalla lista (basta aggiungere un elemento in testa o in coda ed aggiornare
- un puntatore), e relativamente veloce da attraversare in ordine sequenziale
- (seguendo i puntatori), è invece relativamente lenta nell'accesso casuale e
- nella ricerca.} i nuovi messaggi vengono inseriti in coda alla lista e
-vengono letti dalla cima, in fig.~\ref{fig:ipc_mq_schema} si è riportato lo
-schema con cui queste strutture vengono mantenute dal kernel.\footnote{lo
- schema illustrato in fig.~\ref{fig:ipc_mq_schema} è in realtà una
- semplificazione di quello usato effettivamente fino ai kernel della serie
- 2.2.x, nei kernel della serie 2.4.x la gestione delle code di messaggi è
- stata modificata ed è effettuata in maniera diversa; abbiamo mantenuto lo
- schema precedente in quanto illustra comunque in maniera più che adeguata i
- principi di funzionamento delle code di messaggi.}
+Una coda di messaggi è costituita da una \itindex{linked~list}\textit{linked
+ list};\footnote{una \textit{linked list} è una tipica struttura di dati,
+ organizzati in una lista in cui ciascun elemento contiene un puntatore al
+ successivo. In questo modo la struttura è veloce nell'estrazione ed
+ immissione dei dati dalle estremità dalla lista (basta aggiungere un
+ elemento in testa o in coda ed aggiornare un puntatore), e relativamente
+ veloce da attraversare in ordine sequenziale (seguendo i puntatori), è
+ invece relativamente lenta nell'accesso casuale e nella ricerca.} i nuovi
+messaggi vengono inseriti in coda alla lista e vengono letti dalla cima, in
+fig.~\ref{fig:ipc_mq_schema} si è riportato lo schema con cui queste strutture
+vengono mantenute dal kernel.\footnote{lo schema illustrato in
+ fig.~\ref{fig:ipc_mq_schema} è in realtà una semplificazione di quello usato
+ effettivamente fino ai kernel della serie 2.2.x, nei kernel della serie
+ 2.4.x la gestione delle code di messaggi è stata modificata ed è effettuata
+ in maniera diversa; abbiamo mantenuto lo schema precedente in quanto
+ illustra comunque in maniera più che adeguata i principi di funzionamento
+ delle code di messaggi.}
\begin{figure}[!htb]
\footnotesize \centering
funzioni \func{select} e \func{poll}. Questo rende molto scomodo usare più di
una di queste strutture alla volta; ad esempio non si può scrivere un server
che aspetti un messaggio su più di una coda senza fare ricorso ad una tecnica
-di \textit{polling}\index{\textit{polling}} che esegua un ciclo di attesa su
+di \textit{polling}\itindex{polling} che esegua un ciclo di attesa su
ciascuna di esse.
Come esempio dell'uso delle code di messaggi possiamo riscrivere il nostro
Nella struttura viene memorizzato il riferimento alle operazioni richieste
(nel campo \var{sops}, che è un puntatore ad una struttura \struct{sembuf}) e
al processo corrente (nel campo \var{sleeper}) poi quest'ultimo viene messo
-stato di attesa e viene invocato lo scheduler\index{\textit{scheduler}} per
-passare all'esecuzione di un altro processo.
+stato di attesa e viene invocato lo scheduler\itindex{scheduler} per passare
+all'esecuzione di un altro processo.
Se invece tutte le operazioni possono avere successo queste vengono eseguite
immediatamente, dopo di che il kernel esegue una scansione della coda di
il creatore del segmento, oppure l'amministratore. Compiuta l'operazione
aggiorna anche il valore del campo \var{shm\_ctime}.
\item[\const{SHM\_LOCK}] Abilita il \textit{memory
- locking}\index{\textit{memory~locking}}\footnote{impedisce cioè che la
- memoria usata per il segmento venga salvata su disco dal meccanismo della
- memoria virtuale\index{memoria~virtuale}; si ricordi quanto trattato in
+ locking}\itindex{memory~locking}\footnote{impedisce cioè che la memoria
+ usata per il segmento venga salvata su disco dal meccanismo della memoria
+ virtuale\index{memoria~virtuale}; si ricordi quanto trattato in
sez.~\ref{sec:proc_mem_lock}.} sul segmento di memoria condivisa. Solo
l'amministratore può utilizzare questo comando.
\item[\const{SHM\_UNLOCK}] Disabilita il \textit{memory
- locking}\index{\textit{memory~locking}} sul segmento di memoria condivisa.
- Solo l'amministratore può utilizzare questo comando.
+ locking}\itindex{memory~locking} sul segmento di memoria condivisa. Solo
+ l'amministratore può utilizzare questo comando.
\end{basedescript}
i primi tre comandi sono gli stessi già visti anche per le code di messaggi e
gli insiemi di semafori, gli ultimi due sono delle estensioni specifiche
sez.~\ref{sec:file_open}) che prevede\footnote{questo è quanto dettato dallo
standard POSIX.1, ciò non toglie che in alcune implementazioni questa
tecnica possa non funzionare; in particolare per Linux, nel caso di NFS, si
- è comunque soggetti alla possibilità di una race
- condition\index{\textit{race~condition}}.} che essa ritorni un errore quando
+ è comunque soggetti alla possibilità di una \textit{race
+ condition}\itindex{race~condition}.} che essa ritorni un errore quando
usata con i flag di \const{O\_CREAT} e \const{O\_EXCL}. In tal modo la
creazione di un \textsl{file di lock} può essere eseguita atomicamente, il
processo che crea il file con successo si può considerare come titolare del
sincronizzazione: anzitutto in caso di terminazione imprevista del processo,
si lascia allocata la risorsa (il \textsl{file di lock}) e questa deve essere
sempre cancellata esplicitamente. Inoltre il controllo della disponibilità
-può essere eseguito solo con una tecnica di
-\textit{polling}\index{\textit{polling}}, ed è quindi molto inefficiente.
+può essere eseguito solo con una tecnica di \textit{polling}\itindex{polling},
+ed è quindi molto inefficiente.
La tecnica dei file di lock ha comunque una sua utilità, e può essere usata
con successo quando l'esigenza è solo quella di segnalare l'occupazione di una
usare il lock come un \textit{mutex}: per bloccare la risorsa basterà
acquisire il lock, per sbloccarla basterà rilasciare il lock. Una richiesta
fatta con un write lock metterà automaticamente il processo in stato di
-attesa, senza necessità di ricorrere al
-\textit{polling}\index{\textit{polling}} per determinare la disponibilità
-della risorsa, e al rilascio della stessa da parte del processo che la
-occupava si otterrà il nuovo lock atomicamente.
+attesa, senza necessità di ricorrere al \textit{polling}\itindex{polling} per
+determinare la disponibilità della risorsa, e al rilascio della stessa da
+parte del processo che la occupava si otterrà il nuovo lock atomicamente.
Questo approccio presenta il notevole vantaggio che alla terminazione di un
processo tutti i lock acquisiti vengono rilasciati automaticamente (alla
\subsection{Il \textit{memory mapping} anonimo}
\label{sec:ipc_mmap_anonymous}
+\itindbeg{memory~mapping}
Abbiamo già visto che quando i processi sono \textsl{correlati}\footnote{se
cioè hanno almeno un progenitore comune.} l'uso delle pipe può costituire
una valida alternativa alle code di messaggi; nella stessa situazione si può
nel \textit{memory mapping} anonimo.} Vedremo come utilizzare questa tecnica
più avanti, quando realizzeremo una nuova versione del monitor visto in
sez.~\ref{sec:ipc_sysv_shm} che possa restituisca i risultati via rete.
-
+\itindend{memory~mapping}
\section{Il sistema di comunicazione fra processi di POSIX}
La caratteristica fondamentale dell'interfaccia POSIX è l'abbandono dell'uso
degli identificatori e delle chiavi visti nel SysV IPC, per passare ai
-\textit{Posix IPC names}\index{\textit{Posix~IPC~names}}, che sono
-sostanzialmente equivalenti ai nomi dei file. Tutte le funzioni che creano un
-oggetto di IPC Posix prendono come primo argomento una stringa che indica uno
-di questi nomi; lo standard è molto generico riguardo l'implementazione, ed i
-nomi stessi possono avere o meno una corrispondenza sul filesystem; tutto
-quello che è richiesto è che:
+\textit{Posix IPC names}\itindex{Posix~IPC~names}, che sono sostanzialmente
+equivalenti ai nomi dei file. Tutte le funzioni che creano un oggetto di IPC
+Posix prendono come primo argomento una stringa che indica uno di questi nomi;
+lo standard è molto generico riguardo l'implementazione, ed i nomi stessi
+possono avere o meno una corrispondenza sul filesystem; tutto quello che è
+richiesto è che:
\begin{itemize}
\item i nomi devono essere conformi alle regole che caratterizzano i
- \index{\textit{pathname}}\textit{pathname}, in particolare non essere più
- lunghi di \const{PATH\_MAX} byte e terminati da un carattere nullo.
+ \itindex{pathname}\textit{pathname}, in particolare non essere più lunghi di
+ \const{PATH\_MAX} byte e terminati da un carattere nullo.
\item se il nome inizia per una \texttt{/} chiamate differenti allo stesso
nome fanno riferimento allo stesso oggetto, altrimenti l'interpretazione del
nome dipende dall'implementazione.
(rispettivamente \file{/dev/shm} e \file{/dev/mqueue}, per i dettagli si
faccia riferimento a sez.~\ref{sec:ipc_posix_shm} e
sez.~\ref{sec:ipc_posix_mq}) ed i nomi specificati nelle relative funzioni
-sono considerati come un \index{\textit{pathname}!assoluto}\textit{pathname}
+sono considerati come un \itindsub{pathname}{assoluto}\textit{pathname}
assoluto (comprendente eventuali sottodirectory) rispetto a queste radici.
Il vantaggio degli oggetti di IPC POSIX è comunque che essi vengono inseriti
%
\newcommand{\cmd}[1]{\texttt{#1}} % shell command
\newcommand{\code}[1]{\texttt{#1}} % for simple code
+
\newcommand{\func}[1]{%
-\index{#1@{{\tt {#1}} (funzione)}}\texttt{#1}%
+\index{funzione!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (funzione)}}\texttt{#1}%
}
+
\newcommand{\funcd}[1]{%
-\index{#1@{{\tt {#1}} (funzione)}!definizione di}\texttt{#1}%
+\index{funzione!{#1}@{{\tt {#1}}}!definizione di}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (funzione)}!definizione di}\texttt{#1}%
}
+
\newcommand{\macro}[1]{%
-\index{#1@{{\tt {#1}} (macro)}}\texttt{#1}%
+\index{macro!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (macro)}}\texttt{#1}%
}
+
\newcommand{\errcode}[1]{%
-\index{#1@{{\tt {#1}} (errore)}}\texttt{#1}%
+\index{errore!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (errore)}}\texttt{#1}%
}
+
\newcommand{\errval}[1]{\texttt{#1}} % value
\newcommand{\var}[1]{\texttt{#1}} % variable
\newcommand{\val}[1]{\texttt{#1}} % value
+
\newcommand{\const}[1]{%
-\index{#1@{{\tt {#1}} (costante)}}\texttt{#1}%
+\index{costante!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (costante)}}\texttt{#1}%
} % constant name
+
\newcommand{\direct}[1]{%
-\index{#1@{{\tt {#1}} (direttiva)}}\texttt{#1}%
+\index{direttiva!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (direttiva)}}\texttt{#1}%
} % constant name
+
\newcommand{\file}[1]{\texttt{#1}} % file name
\newcommand{\link}[1]{\texttt{#1}} % html link
\newcommand{\ctyp}[1]{\texttt{#1}} % C standard type
+
\newcommand{\type}[1]{%
-\index{#1@{{\tt {#1}} (tipo)}}\texttt{#1}%
+\index{tipo!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (tipo)}}\texttt{#1}%
} % system type
\newcommand{\struct}[1]{%
-\index{#1@{{\tt {#1}} (struttura dati)}}\texttt{#1}%
+\index{struttura dati!{#1}@{{\tt {#1}}}}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (struttura dati)}}\texttt{#1}%
} % struttura dati
\newcommand{\structd}[1]{%
-\index{#1@{{\tt {#1}} (struttura dati)}!definizione di}\texttt{#1}%
+\index{struttura dati!{#1}@{{\tt {#1}}}!definizione di}\texttt{#1}%
+%\index{#1@{{\tt {#1}} (struttura dati)}!definizione di}\texttt{#1}%
} % struttura dati
\newcommand{\param}[1]{\texttt{#1}} % function parameter
\newcommand{\acr}[1]{\textsl{#1}} % acrostic (for pid, suid, ecc.)
+\newcommand{\itindex}[1]{%
+\index{#1@{\textit{#1}}}%
+}
+
+\newcommand{\itindbeg}[1]{%
+\index{#1@{\textit{#1}}|(}%
+}
+\newcommand{\itindend}[1]{%
+\index{#1@{\textit{#1}}|)}%
+}
+\newcommand{\itindsub}[2]{%
+\index{#1@{\textit{#1}}!#2}%
+}
% Aggiunte di Mirko per la gestione delle tabelle complicate come immagini
% nella traslazione in HTML
Questa differenza comporta ovviamente che anche le modalità con cui si usano i
socket UDP sono completamente diverse rispetto ai socket TCP, ed in
particolare non esistendo il concetto di connessione non esiste il meccanismo
-del \textit{three way handshake} né quello degli stati del protocollo. In
-realtà tutto quello che avviene nella comunicazione attraverso dei socket UDP
-è la trasmissione di un pacchetto da un client ad un server o viceversa,
-secondo lo schema illustrato in fig.~\ref{fig:UDP_packet-exchange}.
+del \itindex{three~way~handshake}\textit{three way handshake} né quello degli
+stati del protocollo. In realtà tutto quello che avviene nella comunicazione
+attraverso dei socket UDP è la trasmissione di un pacchetto da un client ad un
+server o viceversa, secondo lo schema illustrato in
+fig.~\ref{fig:UDP_packet-exchange}.
\begin{figure}[htb]
\centering
opportunamente inizializzati con i puntatori alle variabili dove la struttura
contenente quest'ultimo e la relativa lunghezza saranno scritti (si noti che
\param{fromlen} è un valore intero ottenuto come
-\index{\textit{value~result~argument}}\textit{value result argument}). Se non
-si è interessati a questa informazione, entrambi gli argomenti devono essere
+\itindex{value~result~argument}\textit{value result argument}). Se non si è
+interessati a questa informazione, entrambi gli argomenti devono essere
inizializzati al valore \const{NULL}.
Una differenza fondamentale del comportamento di queste funzioni rispetto alle
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.
+ fault}\itindex{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
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.
+ fault}\itindex{page~fault} mandando un segnale \const{SIGSEGV} al processo,
+che normalmente ne causa la terminazione immediata.
È pertanto importante capire come viene strutturata \textsl{la memoria
- virtuale}\index{\textit{page~fault}} di un processo. Essa viene divisa in
+ virtuale}\index{memoria~virtuale} di un processo. Essa viene divisa in
\textsl{segmenti}, cioè un insieme contiguo di indirizzi virtuali ai quali il
processo può accedere. Solitamente un programma C viene suddiviso nei
seguenti segmenti:
Il problema più comune e più difficile da risolvere che si incontra con le
routine di allocazione è quando non viene opportunamente liberata la memoria
non più utilizzata, quello che in inglese viene chiamato \textit{memory
- leak}\index{\textit{memory~leak}}, cioè una \textsl{perdita di memoria}.
+ leak}\itindex{memory~leak}, cioè una \textsl{perdita di memoria}.
Un caso tipico che illustra il problema è quello in cui in una subroutine si
alloca della memoria per uso locale senza liberarla prima di uscire. La
momento, in corrispondenza ad una qualunque chiamata di \func{malloc}, che può
essere in una sezione del codice che non ha alcuna relazione con la subroutine
che contiene l'errore. Per questo motivo è sempre molto difficile trovare un
-\textit{memory leak}\index{\textit{memory~leak}}.
+\textit{memory leak}\itindex{memory~leak}.
In C e C++ il problema è particolarmente sentito. In C++, per mezzo della
-programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente
-ridimensionato attraverso l'uso accurato di appositi oggetti come gli
-\textit{smartpointers}. Questo però va a scapito delle prestazioni
-dell'applicazione in esecuzione.
-
-In altri linguaggi come il java e recentemente il C\# il problema non si pone
-nemmeno perché la gestione della memoria viene fatta totalmente in maniera
-automatica, ovvero il programmatore non deve minimamente preoccuparsi di
-liberare la memoria allocata precedentemente quando non serve più, poiché
-l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta
-\index{\textit{garbage~collection}}\textit{garbage collection}. In tal caso,
-attraverso meccanismi simili a quelli del \textit{reference counting}, quando
-una zona di memoria precedentemente allocata non è più riferita da nessuna
-parte del codice in esecuzione, può essere deallocata automaticamente in
-qualunque momento dall'infrastruttura.
-
-Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione
-(inoltre le applicazioni sviluppate con tali linguaggi di solito non sono
-eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria
-la presenza di una infrastruttura per la loro interpretazione e pertanto hanno
-di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni
-compilate direttamente). Questo comporta però il problema della non
-predicibilità del momento in cui viene deallocata la memoria precedentemente
-allocata da un oggetto.
+programmazione ad oggetti, il problema dei \textit{memory
+ leak}\itindex{memory~leak} è notevolmente ridimensionato attraverso l'uso
+accurato di appositi oggetti come gli \textit{smartpointers}. Questo però in
+genere va a scapito delle prestazioni dell'applicazione in esecuzione.
+
+% In altri linguaggi come il java e recentemente il C\# il problema non si pone
+% nemmeno perché la gestione della memoria viene fatta totalmente in maniera
+% automatica, ovvero il programmatore non deve minimamente preoccuparsi di
+% liberare la memoria allocata precedentemente quando non serve più, poiché
+% l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta
+% \index{\textit{garbage~collection}}\textit{garbage collection}. In tal caso,
+% attraverso meccanismi simili a quelli del \textit{reference counting}, quando
+% una zona di memoria precedentemente allocata non è più riferita da nessuna
+% parte del codice in esecuzione, può essere deallocata automaticamente in
+% qualunque momento dall'infrastruttura.
+
+% Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione
+% (inoltre le applicazioni sviluppate con tali linguaggi di solito non sono
+% eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria
+% la presenza di una infrastruttura per la loro interpretazione e pertanto hanno
+% di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni
+% compilate direttamente). Questo comporta però il problema della non
+% predicibilità del momento in cui viene deallocata la memoria precedentemente
+% allocata da un oggetto.
Per limitare l'impatto di questi problemi, e semplificare la ricerca di
eventuali errori, l'implementazione delle routine di allocazione delle
\label{sec:proc_mem_sbrk_alloca}
Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
-problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in
-precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
-nello heap usa il segmento di stack della funzione corrente. La sintassi è
-identica a quella di \func{malloc}, il suo prototipo è:
+problemi di \textit{memory leak}\itindex{memory~leak} descritti in precedenza,
+è la funzione \funcd{alloca}, che invece di allocare la memoria nello heap usa
+il segmento di stack della funzione corrente. La sintassi è identica a quella
+di \func{malloc}, il suo prototipo è:
\begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
Alloca \param{size} byte nello stack.
rilasciata automaticamente al ritorno della funzione.
Come è evidente questa funzione ha molti vantaggi, anzitutto permette di
-evitare alla radice i problemi di memory leak\index{\textit{memory~leak}},
+evitare alla radice i problemi di \textit{memory leak}\itindex{memory~leak},
dato che non serve più la deallocazione esplicita; inoltre la deallocazione
automatica funziona anche quando si usa \func{longjmp} per uscire da una
subroutine con un salto non locale da una funzione (vedi
crittografia richiedono il blocco di alcune pagine di memoria.
\end{itemize}
-\index{\textit{memory~locking}|(}
+\itindbeg{memory~locking}
Il meccanismo che previene la paginazione\index{paginazione} di parte della
memoria virtuale di un processo è chiamato \textit{memory locking} (o
\textsl{blocco della memoria}). Il blocco è sempre associato alle pagine della
memoria 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 i \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.}
+ereditati dai processi figli.\footnote{ma siccome Linux usa il
+ \itindex{copy~on~write}\textit{copy on write} (vedi
+ sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio sono mantenuti
+ sullo stesso segmento di RAM del padre, quindi fintanto che un figlio non
+ scrive su un segmento, può usufruire del \textit{memory lock} del padre.}
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
In ogni caso un processo real-time che deve entrare in una sezione critica
deve provvedere a riservare memoria sufficiente prima dell'ingresso, per
scongiurare l'occorrenza di un eventuale \textit{page
- fault}\index{\textit{page~fault}} causato dal meccanismo di \textit{copy on
- write}\index{\textit{copy~on~write}}. Infatti se nella sezione critica si
-va ad utilizzare memoria che non è ancora stata riportata in RAM si potrebbe
-avere un page fault durante l'esecuzione della stessa, con conseguente
-rallentamento (probabilmente inaccettabile) dei tempi di esecuzione.
+ fault}\itindex{page~fault} causato dal meccanismo di \textit{copy on
+ write}\itindex{copy~on~write}. Infatti se nella sezione critica si va ad
+utilizzare memoria che non è ancora stata riportata in RAM si potrebbe avere
+un \itindex{page~fault}\textit{page fault} durante l'esecuzione della stessa,
+con conseguente rallentamento (probabilmente inaccettabile) dei tempi di
+esecuzione.
In genere si ovvia a questa problematica chiamando una funzione che ha
allocato una quantità sufficientemente ampia di variabili automatiche, in modo
che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri
che esse siano state effettivamente portate in memoria, ci si scrive sopra.
\index{memoria~virtuale|)}
-\index{\textit{memory~locking}|)}
+\itindend{memory~locking}
Talvolta però è necessario che la funzione possa restituire indietro alla
funzione chiamante un valore relativo ad uno dei suoi argomenti. Per far
-questo si usa il cosiddetto
-\index{\textit{value~result~argument}}\textit{value result argument}, si passa
-cioè, invece di una normale variabile, un puntatore alla stessa; vedremo
-alcuni esempi di questa modalità nelle funzioni che gestiscono i socket (in
-sez.~\ref{sec:TCP_functions}), in cui, per permettere al kernel di restituire
-informazioni sulle dimensioni delle strutture degli indirizzi utilizzate,
-viene usato questo meccanismo.
+questo si usa il cosiddetto \itindex{value~result~argument}\textit{value
+ result argument}, si passa cioè, invece di una normale variabile, un
+puntatore alla stessa; vedremo alcuni esempi di questa modalità nelle funzioni
+che gestiscono i socket (in sez.~\ref{sec:TCP_functions}), in cui, per
+permettere al kernel di restituire informazioni sulle dimensioni delle
+strutture degli indirizzi utilizzate, viene usato questo meccanismo.
\subsection{Il passaggio di un numero variabile di argomenti}
\end{figure}
Come accennato in sez.~\ref{sec:intro_unix_struct} è lo
-\textit{scheduler}\index{\textit{scheduler}} che decide quale processo mettere
-in esecuzione; esso viene eseguito ad ogni system call ed ad ogni
+\textit{scheduler}\itindex{scheduler} che decide quale processo mettere in
+esecuzione; esso viene eseguito ad ogni system call ed ad ogni
interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa
parte.} (ma può essere anche attivato esplicitamente). Il timer di sistema
provvede comunque a che esso sia invocato periodicamente, generando un
sez.~\ref{sec:sys_unix_time}).}
%Si ha cioè un interrupt dal timer ogni centesimo di secondo.
-Ogni volta che viene eseguito, lo \textit{scheduler}\index{\textit{scheduler}}
+Ogni volta che viene eseguito, lo \textit{scheduler}\itindex{scheduler}
effettua il calcolo delle priorità dei vari processi attivi (torneremo su
questo in sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba
essere posto in esecuzione fino alla successiva invocazione.
candidato per generare ulteriori indicatori associati al processo di cui
diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la
funzione \func{tempnam} (si veda sez.~\ref{sec:file_temp_file}) usa il
-\acr{pid} per generare un \index{\textit{pathname}}\textit{pathname} univoco,
-che non potrà essere replicato da un altro processo che usi la stessa
-funzione.
+\acr{pid} per generare un \itindex{pathname}\textit{pathname} univoco, che non
+potrà essere replicato da un altro processo che usi la stessa funzione.
Tutti i processi figli dello stesso processo padre sono detti
\textit{sibling}, questa è una delle relazioni usate nel \textsl{controllo di
Per quanto riguarda la gestione della memoria, in generale il segmento di
testo, che è identico per i due processi, è condiviso e tenuto in read-only
per il padre e per i figli. Per gli altri segmenti Linux utilizza la tecnica
-del \textit{copy on write}\index{\textit{copy~on~write}}; questa tecnica
+del \textit{copy on write}\itindex{copy~on~write}; questa tecnica
comporta che una pagina di memoria viene effettivamente copiata per il nuovo
processo solo quando ci viene effettuata sopra una scrittura (e si ha quindi
una reale differenza fra padre e figlio). In questo modo si rende molto più
Esaminiamo questo risultato: una prima conclusione che si può trarre è che non
si può dire quale processo fra il padre ed il figlio venga eseguito per
primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo
- scheduler\index{\textit{scheduler}} di Ingo Molnar che esegue sempre per
- primo il figlio; per mantenere la portabilità è opportuno non fare comunque
+ scheduler\itindex{scheduler} di Ingo Molnar che esegue sempre per primo il
+ figlio; per mantenere la portabilità è opportuno non fare comunque
affidamento su questo comportamento.} dopo la chiamata a \func{fork};
dall'esempio si può notare infatti come nei primi due cicli sia stato eseguito
per primo il padre (con la stampa del \acr{pid} del nuovo processo) per poi
istruzioni del codice fra padre e figli, né sull'ordine in cui questi potranno
essere messi in esecuzione. Se è necessaria una qualche forma di precedenza
occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il
-rischio di incorrere nelle cosiddette
-\textit{race condition}\index{\textit{race~condition}}
-(vedi sez.~\ref{sec:proc_race_cond}).
+rischio di incorrere nelle cosiddette \textit{race
+ condition}\itindex{race~condition} (vedi sez.~\ref{sec:proc_race_cond}).
Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
processi completamente separati, le modifiche delle variabili nei processi
comune dopo l'esecuzione di una \func{fork} è la seguente:
\begin{itemize*}
\item i file aperti e gli eventuali flag di
- \textit{close-on-exec}\index{\textit{close-on-exec}} impostati (vedi
+ \textit{close-on-exec}\itindex{close-on-exec} impostati (vedi
sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl});
\item gli identificatori per il controllo di accesso: l'\textsl{user-ID
reale}, il \textsl{group-ID reale}, l'\textsl{user-ID effettivo}, il
\func{fork} veniva fatta solo per poi eseguire una \func{exec}. La funzione
venne introdotta in BSD per migliorare le prestazioni.
-Dato che Linux supporta il \textit{copy on
- write}\index{\textit{copy~on~write}} la perdita di prestazioni è
-assolutamente trascurabile, e l'uso di questa funzione (che resta un caso
-speciale della system call \func{\_\_clone}) è deprecato; per questo eviteremo
-di trattarla ulteriormente.
+Dato che Linux supporta il \textit{copy on write}\itindex{copy~on~write} la
+perdita di prestazioni è assolutamente trascurabile, e l'uso di questa
+funzione (che resta un caso speciale della system call \func{\_\_clone}) è
+deprecato; per questo eviteremo di trattarla ulteriormente.
\subsection{La conclusione di un processo}
Le altre quattro funzioni si limitano invece a cercare di eseguire il file
indicato dall'argomento \param{path}, che viene interpretato come il
-\index{\textit{pathname}}\textit{pathname} del programma.
+\itindex{pathname}\textit{pathname} del programma.
\begin{figure}[htb]
\centering
sez.~\ref{sec:sig_gen_beha}).
La gestione dei file aperti dipende dal valore che ha il flag di
-\textit{close-on-exec}\index{\textit{close-on-exec}} (vedi anche
+\textit{close-on-exec}\itindex{close-on-exec} (vedi anche
sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è
impostato vengono chiusi, tutti gli altri file restano aperti. Questo
significa che il comportamento predefinito è che i file restano aperti
Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse
attraverso una \func{exec}, in genere questo è fatto dalla funzione
\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola
-l'impostazione del flag di
-\textit{close-on-exec}\index{\textit{close-on-exec}} sulle directory che apre,
-in maniera trasparente all'utente.
+l'impostazione del flag di \textit{close-on-exec}\itindex{close-on-exec} sulle
+directory che apre, in maniera trasparente all'utente.
Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale}
restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per
Anche queste funzioni sono un'estensione specifica di Linux, e non richiedono
nessun privilegio. I valori sono restituiti negli argomenti, che vanno
specificati come puntatori (è un altro esempio di
-\index{\textit{value~result~argument}}\textit{value result argument}). Si noti
-che queste funzioni sono le uniche in grado di leggere gli identificatori del
+\itindex{value~result~argument}\textit{value result argument}). Si noti che
+queste funzioni sono le uniche in grado di leggere gli identificatori del
gruppo \textit{saved}.
\label{sec:proc_priority}
In questa sezione tratteremo più approfonditamente i meccanismi con il quale
-lo \textit{scheduler}\index{\textit{scheduler}} assegna la CPU ai vari
+lo \textit{scheduler}\itindex{scheduler} assegna la CPU ai vari
processi attivi. In particolare prenderemo in esame i vari meccanismi con cui
viene gestita l'assegnazione del tempo di CPU, ed illustreremo le varie
funzioni di gestione.
\subsection{I meccanismi di \textit{scheduling}}
\label{sec:proc_sched}
+\itindbeg{scheduler}
La scelta di un meccanismo che sia in grado di distribuire in maniera efficace
il tempo di CPU per l'esecuzione dei processi è sempre una questione delicata,
ed oggetto di numerose ricerche; in generale essa dipende in maniera
cui non esiste un meccanismo che sia valido per tutti gli usi.
La caratteristica specifica di un sistema multitasking come Linux è quella del
-cosiddetto \textit{prehemptive multitasking}: questo significa che al
-contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative
+cosiddetto \itindex{prehemptive~multitasking}\textit{prehemptive
+ multitasking}: questo significa che al contrario di altri sistemi (che usano
+invece il cosiddetto \itindex{cooperative~multitasking}\textit{cooperative
multitasking}) non sono i singoli processi, ma il kernel stesso a decidere
quando la CPU deve essere passata ad un altro processo. Come accennato in
sez.~\ref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
-apposita del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, il cui
-scopo è quello di distribuire al meglio il tempo di CPU fra i vari processi.
+apposita del kernel, lo \textit{scheduler}, il cui scopo è quello di
+distribuire al meglio il tempo di CPU fra i vari processi.
La cosa è resa ancora più complicata dal fatto che con le architetture
multi-processore si deve anche scegliere quale sia la CPU più opportuna da
nell'esecuzione.
Il meccanismo usato da Linux è piuttosto semplice,\footnote{in realtà nella
- serie 2.6.x lo \textit{scheduler} è stato riscritto da zero e può usare
- diversi algoritmi, selezionabili sia in fase di compilazione, che, nelle
- versioni più recenti, all'avvio (addirittura è stato ideato un sistema
- modulare che permette di cambiare lo scheduler al volo, che comunque non è
- incluso nel kernel ufficiale).} ad ogni processo è assegnata una
-\textit{time-slice}, cioè un intervallo di tempo (letteralmente una fetta) per
-il quale esso deve essere eseguito. Il valore della \textit{time-slice} è
-controllato dalla cosiddetta \textit{nice} (o \textit{niceness}) del processo.
-Essa è contenuta nel campo \var{nice} di \struct{task\_struct}; tutti i
-processi vengono creati con lo stesso valore, ed essa specifica il valore
-della durata iniziale della \textit{time-slice} che viene assegnato ad un
-altro campo della struttura (\var{counter}) quando il processo viene eseguito
-per la prima volta e diminuito progressivamente ad ogni interruzione del
-timer.
-
-Durante la sua esecuzione lo scheduler\index{\textit{scheduler}} scandisce la
-coda dei processi in stato \textit{runnable} associando, in base al valore di
-\var{counter}, un peso ad ogni processo in attesa di esecuzione,\footnote{il
- calcolo del peso in realtà è un po' più complicato, ad esempio nei sistemi
- multiprocessore viene favorito un processo eseguito sulla stessa CPU, e a
- parità del valore di \var{counter} viene favorito chi ha una priorità più
- elevata.} chi ha il peso più alto verrà posto in esecuzione, ed il
-precedente processo sarà spostato in fondo alla coda. Dato che ad ogni
-interruzione del timer il valore di \var{counter} del processo corrente viene
-diminuito, questo assicura che anche i processi con priorità più bassa
-verranno messi in esecuzione.
+ serie 2.6.x lo scheduler è stato riscritto da zero e può usare diversi
+ algoritmi, selezionabili sia in fase di compilazione, che, nelle versioni
+ più recenti, all'avvio (addirittura è stato ideato un sistema modulare che
+ permette di cambiare lo scheduler al volo, che comunque non è incluso nel
+ kernel ufficiale).} ad ogni processo è assegnata una \textit{time-slice},
+cioè un intervallo di tempo (letteralmente una fetta) per il quale esso deve
+essere eseguito. Il valore della \textit{time-slice} è controllato dalla
+cosiddetta \textit{nice} (o \textit{niceness}) del processo. Essa è contenuta
+nel campo \var{nice} di \struct{task\_struct}; tutti i processi vengono creati
+con lo stesso valore, ed essa specifica il valore della durata iniziale della
+\textit{time-slice} che viene assegnato ad un altro campo della struttura
+(\var{counter}) quando il processo viene eseguito per la prima volta e
+diminuito progressivamente ad ogni interruzione del timer.
+
+Durante la sua esecuzione lo scheduler scandisce la coda dei processi in stato
+\textit{runnable} associando, in base al valore di \var{counter}, un peso ad
+ogni processo in attesa di esecuzione,\footnote{il calcolo del peso in realtà
+ è un po' più complicato, ad esempio nei sistemi multiprocessore viene
+ favorito un processo eseguito sulla stessa CPU, e a parità del valore di
+ \var{counter} viene favorito chi ha una priorità più elevata.} chi ha il
+peso più alto verrà posto in esecuzione, ed il precedente processo sarà
+spostato in fondo alla coda. Dato che ad ogni interruzione del timer il
+valore di \var{counter} del processo corrente viene diminuito, questo assicura
+che anche i processi con priorità più bassa verranno messi in esecuzione.
La priorità di un processo è così controllata attraverso il valore di
\var{nice}, che stabilisce la durata della \textit{time-slice}; per il
Adeos gestiti dalle code del nano-kernel), in modo da poterli controllare
direttamente qualora ci sia la necessità di avere un processo con priorità
più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
-page fault\index{\textit{page~fault}} si possono avere ritardi non previsti.
+\textit{page fault}\itindex{page~fault} si possono avere ritardi non previsti.
Se l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di
controllo della memoria virtuale (vedi sez.~\ref{sec:proc_mem_lock}), il primo
non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di
cui si sia assegnata la massima priorità assoluta, in modo da poter essere
comunque in grado di rientrare nel sistema.
-Quando c'è un processo con priorità assoluta lo
-scheduler\index{\textit{scheduler}} lo metterà in esecuzione prima di ogni
-processo normale. In caso di più processi sarà eseguito per primo quello con
-priorità assoluta più alta. Quando ci sono più processi con la stessa priorità
-assoluta questi vengono tenuti in una coda e tocca al kernel decidere quale
-deve essere eseguito. Il meccanismo con cui vengono gestiti questi processi
-dipende dalla politica di scheduling che si è scelto; lo standard ne prevede
-due:
+Quando c'è un processo con priorità assoluta lo scheduler lo metterà in
+esecuzione prima di ogni processo normale. In caso di più processi sarà
+eseguito per primo quello con priorità assoluta più alta. Quando ci sono più
+processi con la stessa priorità assoluta questi vengono tenuti in una coda e
+tocca al kernel decidere quale deve essere eseguito. Il meccanismo con cui
+vengono gestiti questi processi dipende dalla politica di scheduling che si è
+scelto; lo standard ne prevede due:
\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}}
\item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito
fintanto che non cede volontariamente la CPU (con \func{sched\_yield}), si
funzioni che permettono di controllare in maniera più dettagliata la scelta di
quale processore utilizzare per eseguire un certo programma. Uno dei problemi
che si pongono nei sistemi multiprocessore è infatti quello
-dell'\textsl{effetto ping-pong}.\index{\textsl{effetto ping-pong}} Può
-accadere cioè che lo scheduler, quando riavvia un processo precedentemente
-interrotto, scegliendo il primo processore disponibile lo faccia eseguire da
-un processore diverso rispetto a quello su cui era stato eseguito in
-precedenza. Se il processo passa da un processore all'altro in questo modo
-(cosa che avveniva abbastanza di frequente con i kernel della seria 2.4.x) si
-ha l'\textsl{effetto ping-pong}.
+dell'\textsl{effetto ping-pong}.\index{effetto~ping-pong} Può accadere cioè
+che lo scheduler, quando riavvia un processo precedentemente interrotto,
+scegliendo il primo processore disponibile lo faccia eseguire da un processore
+diverso rispetto a quello su cui era stato eseguito in precedenza. Se il
+processo passa da un processore all'altro in questo modo (cosa che avveniva
+abbastanza di frequente con i kernel della seria 2.4.x) si ha
+l'\textsl{effetto ping-pong}.
Questo tipo di comportamento può generare dei seri problemi di prestazioni;
infatti tutti i processori moderni utilizzano una memoria interna (la
diventa serio quando si verifica l'\textsl{effetto ping-pong}, in tal caso
infatti un processo \textsl{rimbalza} continuamente da un processore all'altro
e si ha una continua invalidazione della cache, che non diventa mai
-disponibile.
+disponibile.
+\itindbeg{CPU~affinity}
Per ovviare a questo tipo di problemi è nato il concetto di \textsl{affinità
- di processore} (o \index{\textit{CPU~affinity}}\textit{CPU affinity}); la
+ di processore} (o \textit{CPU affinity}); la
possibilità cioè di far sì che un processo possa essere assegnato per
l'esecuzione sempre allo stesso processore. Lo scheduler dei kernel della
-serie 2.4.x aveva una scarsa \textit{CPU affinity}, e l'effetto ping-pong era
-comune; con il nuovo scheduler dei kernel della 2.6.x questo problema è stato
-risolto ed esso cerca di mantenere il più possibile ciascun processo sullo
-stesso processore.
+serie 2.4.x aveva una scarsa \textit{CPU affinity}, e
+\index{effetto~ping-pong} l'effetto ping-pong era comune; con il nuovo
+scheduler dei kernel della 2.6.x questo problema è stato risolto ed esso cerca
+di mantenere il più possibile ciascun processo sullo stesso processore.
In certi casi però resta l'esigenza di poter essere sicuri che un processo sia
sempre eseguito dallo stesso processore,\footnote{quella che viene detta
soltanto su un sistema multiprocessore, esse possono comunque essere
utilizzate anche in un sistema con un processore singolo, nel qual caso però
non avranno alcun risultato effettivo.
+\itindend{scheduler}
+\itindend{CPU~affinity}
+
\section{Problematiche di programmazione multitasking}
In un ambiente multitasking il concetto è essenziale, dato che un processo può
essere interrotto in qualunque momento dal kernel che mette in esecuzione un
altro processo o dalla ricezione di un segnale; occorre pertanto essere
-accorti nei confronti delle possibili
-\textit{race condition}\index{\textit{race~condition}} (vedi
-sez.~\ref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase
-in cui non erano ancora state completate.
+accorti nei confronti delle possibili \textit{race
+ condition}\itindex{race~condition} (vedi sez.~\ref{sec:proc_race_cond})
+derivanti da operazioni interrotte in una fase in cui non erano ancora state
+completate.
Nel caso dell'interazione fra processi la situazione è molto più semplice, ed
occorre preoccuparsi della atomicità delle operazioni solo quando si ha a che
\subsection{Le \textit{race condition} ed i \textit{deadlock}}
\label{sec:proc_race_cond}
-\index{\textit{race~condition}|(}
+\itindbeg{race~condition}
Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
diversi operano su una risorsa comune, ed in cui il risultato viene a
dipendere dall'ordine in cui essi effettuano le loro operazioni. Il caso
opportunamente protette da meccanismi di sincronizzazione (torneremo su queste
problematiche di questo tipo in cap.~\ref{cha:IPC}).
-\index{\textit{deadlock}|(}
+\itindbeg{deadlock}
Un caso particolare di \textit{race condition} sono poi i cosiddetti
\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
completo di un servizio, e non il fallimento di una singola operazione. Per
visto in sez.~\ref{sec:proc_atom_oper}; questi problemi infatti possono essere
risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile
eseguire in maniera atomica le operazioni necessarie.
-\index{\textit{race~condition}|)}
-\index{\textit{deadlock}|)}
+\itindend{race~condition}
+\itindend{deadlock}
\subsection{Le funzioni rientranti}
sé stesso, in modo che il cambiamento di \textit{process group} sia immediato
per entrambi; una delle due chiamate sarà ridondante, ma non potendo
determinare quale dei due processi viene eseguito per primo, occorre eseguirle
-comunque entrambe per evitare di esporsi ad una race
-condition\index{\textit{race~condition}}.
+comunque entrambe per evitare di esporsi ad una \textit{race
+ condition}\itindex{race~condition}.
Si noti come nessuna delle funzioni esaminate finora permetta di spostare un
processo da una sessione ad un altra; infatti l'unico modo di far cambiare
\const{SIGQUIT} e \const{SIGTERM}, trattati in sez.~\ref{sec:sig_job_control})
a tutti i processi del raggruppamento di \textit{foreground}; in questo modo
la shell può gestire il blocco e l'interruzione dei vari comandi.
-
+
+% \|
+
Per completare la trattazione delle caratteristiche del job control legate al
terminale di controllo, occorre prendere in considerazione i vari casi legati
alla terminazione anomala dei processi, che sono di norma gestite attraverso
il segnale \const{SIGHUP}. Il nome del segnale deriva da \textit{hungup},
termine che viene usato per indicare la condizione in cui il terminale diventa
-inutilizzabile, (letteralmente sarebbe \textsl{impiccagione}).
+inutilizzabile, (letteralmente sarebbe \textsl{impiccagione}).
Quando si verifica questa condizione, ad esempio se si interrompe la linea, o
va giù la rete o più semplicemente si chiude forzatamente la finestra di
\textit{pathname} del terminale.}
\end{prototype}
-La funzione scrive il \index{\textit{pathname}}\textit{pathname} del terminale
-di controllo del processo chiamante nella stringa posta all'indirizzo
-specificato dall'argomento \param{s}. La memoria per contenere la stringa
-deve essere stata allocata in precedenza ed essere lunga almeno
+La funzione scrive il \itindex{pathname}\textit{pathname} del terminale di
+controllo del processo chiamante nella stringa posta all'indirizzo specificato
+dall'argomento \param{s}. La memoria per contenere la stringa deve essere
+stata allocata in precedenza ed essere lunga almeno
\const{L\_ctermid}\footnote{\const{L\_ctermid} è una delle varie costanti del
sistema, non trattata esplicitamente in sez.~\ref{sec:sys_characteristics}
che indica la dimensione che deve avere una stringa per poter contenere il
Se si passa come argomento \val{NULL} la funzione restituisce il puntatore ad
una stringa statica che può essere sovrascritta da chiamate successive. Si
-tenga presente che il \index{\textit{pathname}}\textit{pathname} restituito
+tenga presente che il \itindex{pathname}\textit{pathname} restituito
potrebbe non identificare univocamente il terminale (ad esempio potrebbe
essere \file{/dev/tty}), inoltre non è detto che il processo possa
effettivamente aprire il terminale.
\const{TOSTOP} & Se abilitato, con il supporto per il job control presente,
genera il segnale \const{SIGTTOU} per un processo in
background che cerca di scrivere sul terminale.\\
- \const{XCASE} & Se settato il terminale funziona solo con le
+ \const{XCASE} & Se impostato il terminale funziona solo con le
maiuscole. L'input è convertito in minuscole tranne per i
caratteri preceduti da una \verb|\|. In output le
maiuscole sono precedute da una \verb|\| e le minuscole
convertite in maiuscole.\\
- \const{DEFECHO}& Se impostate effettua l'eco solo se c'è un processo in
+ \const{DEFECHO}& Se impostato effettua l'eco solo se c'è un processo in
lettura.\\
\const{FLUSHO} & Effettua la cancellazione della coda di uscita. Viene
attivato dal carattere DISCARD. Non è supportato in
Questa è la ragione per cui l'implementazione dei segnali secondo questa
semantica viene chiamata \textsl{inaffidabile}; infatti la ricezione del
segnale e la reinstallazione del suo gestore non sono operazioni atomiche, e
-sono sempre possibili delle race condition\index{\textit{race~condition}}
+sono sempre possibili delle \textit{race condition}\itindex{race~condition}
(sull'argomento vedi quanto detto in sez.~\ref{sec:proc_multi_prog}).
Un altro problema è che in questa semantica non esiste un modo per bloccare i
\textit{delivered}) quando viene eseguita l'azione per esso prevista, mentre
per tutto il tempo che passa fra la generazione del segnale e la sua consegna
esso è detto \textsl{pendente} (o \textit{pending}). In genere questa
-procedura viene effettuata dallo scheduler\index{\textit{scheduler}} quando,
+procedura viene effettuata dallo scheduler\itindex{scheduler} quando,
riprendendo l'esecuzione del processo in questione, verifica la presenza del
segnale nella \struct{task\_struct} e mette in esecuzione il gestore.
Normalmente l'invio al processo che deve ricevere il segnale è immediato ed
avviene non appena questo viene rimesso in esecuzione dallo
-scheduler\index{\textit{scheduler}} che esegue l'azione specificata. Questo a
-meno che il segnale in questione non sia stato bloccato prima della notifica,
-nel qual caso l'invio non avviene ed il segnale resta \textsl{pendente}
+scheduler\itindex{scheduler} che esegue l'azione specificata. Questo a meno
+che il segnale in questione non sia stato bloccato prima della notifica, nel
+qual caso l'invio non avviene ed il segnale resta \textsl{pendente}
indefinitamente. Quando lo si sblocca il segnale \textsl{pendente} sarà subito
notificato. Si tenga presente però che i segnali \textsl{pendenti} non si
accodano, alla generazione infatti il kernel marca un flag nella
Un programma può specificare queste scelte usando le due funzioni
\func{signal} e \func{sigaction} (vedi sez.~\ref{sec:sig_signal} e
-sez.~\ref{sec:sig_sigaction}). Se si è installato un gestore sarà
-quest'ultimo ad essere eseguito alla notifica del segnale. Inoltre il sistema
-farà si che mentre viene eseguito il gestore di un segnale, quest'ultimo
-venga automaticamente bloccato (così si possono evitare race
-condition\index{\textit{race~condition}}).
+sez.~\ref{sec:sig_sigaction}). Se si è installato un gestore sarà quest'ultimo
+ad essere eseguito alla notifica del segnale. Inoltre il sistema farà si che
+mentre viene eseguito il gestore di un segnale, quest'ultimo venga
+automaticamente bloccato (così si possono evitare \textit{race
+ condition}\itindex{race~condition}).
Nel caso non sia stata specificata un'azione, viene utilizzata l'azione
standard che (come vedremo in sez.~\ref{sec:sig_standard}) è propria di ciascun
\label{sec:sig_prog_error}
Questi segnali sono generati quando il sistema, o in certi casi direttamente
-l'hardware (come per i \textit{page fault} non validi) rileva un qualche
-errore insanabile nel programma in esecuzione. In generale la generazione di
-questi segnali significa che il programma ha dei gravi problemi (ad esempio ha
-dereferenziato un puntatore non valido o ha eseguito una operazione aritmetica
-proibita) e l'esecuzione non può essere proseguita.
+l'hardware (come per i \itindex{page~fault}\textit{page fault} non validi)
+rileva un qualche errore insanabile nel programma in esecuzione. In generale
+la generazione di questi segnali significa che il programma ha dei gravi
+problemi (ad esempio ha dereferenziato un puntatore non valido o ha eseguito
+una operazione aritmetica proibita) e l'esecuzione non può essere proseguita.
In genere si intercettano questi segnali per permettere al programma di
terminare in maniera pulita, ad esempio per ripristinare le impostazioni della
nanosecondo, la precisione di \func{nanosleep} è determinata dalla risoluzione
temporale del timer di sistema. Perciò la funzione attenderà comunque il tempo
specificato, ma prima che il processo possa tornare ad essere eseguito
-occorrerà almeno attendere il successivo giro di
-scheduler\index{\textit{scheduler}} e cioè un tempo che a seconda dei casi può
-arrivare fino a 1/\const{HZ}, (sempre che il sistema sia scarico ed il
-processa venga immediatamente rimesso in esecuzione); per questo motivo il
-valore restituito in \param{rem} è sempre arrotondato al multiplo successivo
-di 1/\const{HZ}.
+occorrerà almeno attendere il successivo giro di scheduler\itindex{scheduler}
+e cioè un tempo che a seconda dei casi può arrivare fino a 1/\const{HZ},
+(sempre che il sistema sia scarico ed il processa venga immediatamente rimesso
+in esecuzione); per questo motivo il valore restituito in \param{rem} è sempre
+arrotondato al multiplo successivo di 1/\const{HZ}.
In realtà è possibile ottenere anche pause più precise del centesimo di
secondo usando politiche di scheduling real-time come \const{SCHED\_FIFO} o
Le funzioni esaminate finora fanno riferimento alle modalità più elementari
della gestione dei segnali; non si sono pertanto ancora prese in
-considerazione le tematiche più complesse, collegate alle varie race
-condition\index{\textit{race~condition}} che i segnali possono generare e alla
+considerazione le tematiche più complesse, collegate alle varie \textit{race
+ condition}\itindex{race~condition} che i segnali possono generare e alla
natura asincrona degli stessi.
Affronteremo queste problematiche in questa sezione, partendo da un esempio
Questo codice però, a parte il non gestire il caso in cui si è avuta una
precedente chiamata a \func{alarm} (che si è tralasciato per brevità),
-presenta una pericolosa race condition\index{\textit{race~condition}}.
+presenta una pericolosa \textit{race condition}\itindex{race~condition}.
Infatti, se il processo viene interrotto fra la chiamata di \func{alarm} e
\func{pause}, può capitare (ad esempio se il sistema è molto carico) che il
tempo di attesa scada prima dell'esecuzione di quest'ultima, cosicché essa
sarebbe eseguita dopo l'arrivo di \const{SIGALRM}. In questo caso ci si
-troverebbe di fronte ad un deadlock\index{\textit{deadlock}}, in quanto
-\func{pause} non verrebbe mai più interrotta (se non in caso di un altro
-segnale).
+troverebbe di fronte ad un deadlock\itindex{deadlock}, in quanto \func{pause}
+non verrebbe mai più interrotta (se non in caso di un altro segnale).
Questo problema può essere risolto (ed è la modalità con cui veniva fatto in
SVr2) usando la funzione \func{longjmp} (vedi sez.~\ref{sec:proc_longjmp}) per
Questo è il tipico esempio di caso, già citato in
sez.~\ref{sec:proc_race_cond}, in cui si genera una
-\index{\textit{race~condition}}race condition; infatti, in una situazione in
+\itindex{race~condition}\textit{race condition}; infatti, in una situazione in
cui un segnale è già arrivato (e \var{flag} è già ad 1) se un altro segnale
segnale arriva immediatamente dopo l'esecuzione del controllo (\texttt{\small
6}) ma prima della cancellazione del flag (\texttt{\small 7}), la sua
\subsection{Gli \textsl{insiemi di segnali} o \textit{signal set}}
\label{sec:sig_sigset}
-\index{\textit{signal~set}|(}
+\itindbeg{signal~set}
+
Come evidenziato nel paragrafo precedente, le funzioni di gestione dei segnali
originarie, nate con la semantica inaffidabile, hanno dei limiti non
superabili; in particolare non è prevista nessuna funzione che permetta di
insieme completo ottenuto con \func{sigfillset}. Infine \func{sigismember}
permette di verificare la presenza di uno specifico segnale in un
insieme.
-\index{\textit{signal~set}|)}
+\itindend{signal~set}
\subsection{La funzione \func{sigaction}}
\textit{signal mask}}
\label{sec:sig_sigmask}
-\index{\textit{signal mask}|(}
+\itindbeg{signal~mask}
Come spiegato in sez.~\ref{sec:sig_semantics} tutti i moderni sistemi unix-like
permettono di bloccare temporaneamente (o di eliminare completamente,
impostando \const{SIG\_IGN} come azione) la consegna dei segnali ad un
perduta alla conclusione del terminatore.
Benché con l'uso di \func{sigprocmask} si possano risolvere la maggior parte
-dei casi di race condition\index{\textit{race~condition}} restano aperte
+dei casi di \textit{race condition}\itindex{race~condition} restano aperte
alcune possibilità legate all'uso di \func{pause}; il caso è simile a quello
del problema illustrato nell'esempio di fig.~\ref{fig:sig_sleep_incomplete}, e
cioè la possibilità che il processo riceva il segnale che si intende usare per
\var{sleep\_mask} per riattivare \const{SIGALRM} all'esecuzione di
\func{sigsuspend}.
-In questo modo non sono più possibili race
-condition\index{\textit{race~condition}} dato che \const{SIGALRM} viene
+In questo modo non sono più possibili \textit{race
+ condition}\itindex{race~condition} dato che \const{SIGALRM} viene
disabilitato con \func{sigprocmask} fino alla chiamata di \func{sigsuspend}.
Questo metodo è assolutamente generale e può essere applicato a qualunque
altra situazione in cui si deve attendere per un segnale, i passi sono sempre
\end{enumerate*}
Per quanto possa sembrare strano bloccare la ricezione di un segnale per poi
riabilitarla immediatamente dopo, in questo modo si evita il
-deadlock\index{\textit{deadlock}} dovuto all'arrivo del segnale prima
-dell'esecuzione di \func{sigsuspend}.
-\index{\textit{signal mask}|)}
+deadlock\itindex{deadlock} dovuto all'arrivo del segnale prima dell'esecuzione
+di \func{sigsuspend}.
+
+\itindend{signal~mask}
\subsection{Ulteriori funzioni di gestione}
\begin{minipage}[c]{15cm}
\includestruct{listati/sock_extended_err.h}
\end{minipage}
- \caption{La struttura \structd{sock_extended_err} usata dall'opzione
+ \caption{La struttura \structd{sock\_extended\_err} usata dall'opzione
\const{IP\_RECVERR} per ottenere le informazioni relative agli errori su
un socket.}
\label{fig:sock_extended_err_struct}
\subsection{La struttura del \textit{resolver}}
\label{sec:sock_resolver}
-\index{\textit{resolver}|(}
+\itindbeg{resolver}
La risoluzione dei nomi è associata tradizionalmente al servizio del
\textit{Domain Name Service} che permette di identificare le macchine su
internet invece che per numero IP attraverso il relativo \textsl{nome a
funzioni di libreria, prevedendo un ordine di interrogazione predefinito e
non modificabile (a meno di una ricompilazione delle librerie stesse).}
-\index{\textit{Name~Service~Switch}|(}
+\itindbeg{Name~Service~Switch}
Per risolvere questa serie di problemi la risoluzione dei nomi a dominio
eseguirà dal \textit{resolver} è stata inclusa all'interno di un meccanismo
generico per la risoluzione di corrispondenze fra nomi ed informazioni ad essi
\label{tab:sys_NSS_classes}
\end{table}
-Il sistema del \textit{Name Service Switch} è controllato dal contenuto del
+Il sistema del \textit{Name Service Switch} è controllato dal contenuto del
file \file{/etc/nsswitch.conf}; questo contiene una riga\footnote{seguendo una
convezione comune per i file di configurazione le righe vuote vengono
ignorate e tutto quello che segue un carattere ``\texttt{\#}'' viene
disposizione,\footnote{è cura della implementazione fattane nelle \acr{glibc}
tenere conto della presenza del \textit{Name Service Switch}.} e sono queste
quelle che tratteremo nelle sezioni successive.
-\index{\textit{Name~Service~Switch}|)}
+\itindend{Name~Service~Switch}
\subsection{Le funzioni di interrogazione del \textit{resolver}}
\noindent che, come l'analoga \func{strerror}, restituisce una stringa con un
messaggio di errore già formattato, corrispondente al codice passato come
argomento (che si presume sia dato da \var{h\_errno}).
-\index{\textit{resolver}|)}
-
+\itindend{resolver}
\subsection{La risoluzione dei nomi a dominio}
\label{sec:sock_name_services}
-La principale funzionalità del \index{\textit{resolver}}\textit{resolver}
-resta quella di risolvere i nomi a dominio in indirizzi IP, per cui non ci
+La principale funzionalità del \itindex{resolver}\textit{resolver} resta
+quella di risolvere i nomi a dominio in indirizzi IP, per cui non ci
dedicheremo oltre alle funzioni di richiesta generica ed esamineremo invece le
funzioni a questo dedicate. La prima funzione è \funcd{gethostbyname} il cui
scopo è ottenere l'indirizzo di una stazione noto il suo nome a dominio, il
IPv4, se si vogliono ottenere degli indirizzi IPv6 occorrerà prima impostare
l'opzione \const{RES\_USE\_INET6} nel campo \texttt{\_res.options} e poi
chiamare \func{res\_init} (vedi sez.~\ref{sec:sock_resolver_functions}) per
-modificare le opzioni del \index{\textit{resolver}}\textit{resolver}; dato che
+modificare le opzioni del \itindex{resolver}\textit{resolver}; dato che
questo non è molto comodo è stata definita\footnote{questa è una estensione
fornita dalle \acr{glibc}, disponibile anche in altri sistemi unix-like.}
un'altra funzione, \funcd{gethostbyname2}, il cui prototipo è:
Vediamo allora un primo esempio dell'uso delle funzioni di risoluzione, in
fig.~\ref{fig:mygethost_example} è riportato un estratto del codice di un
programma che esegue una semplice interrogazione al
-\index{\textit{resolver}}\textit{resolver} usando \func{gethostbyname} e poi
-ne stampa a video i risultati. Al solito il sorgente completo, che comprende
-il trattamento delle opzioni ed una funzione per stampare un messaggio di
-aiuto, è nel file \texttt{mygethost.c} dei sorgenti allegati alla guida.
+\itindex{resolver}\textit{resolver} usando \func{gethostbyname} e poi ne
+stampa a video i risultati. Al solito il sorgente completo, che comprende il
+trattamento delle opzioni ed una funzione per stampare un messaggio di aiuto,
+è nel file \texttt{mygethost.c} dei sorgenti allegati alla guida.
Il programma richiede un solo argomento che specifichi il nome da cercare,
senza il quale (\texttt{\small 12--15}) esce con un errore. Dopo di che
i dati, in quanto questa contiene puntatori ad altri dati, che pure possono
essere sovrascritti; per questo motivo, se si vuole salvare il risultato di
una chiamata, occorrerà eseguire quella che si chiama una
-\index{\textit{deep~copy}}\textit{deep copy}.\footnote{si chiama così quella
- tecnica per cui, quando si deve copiare il contenuto di una struttura
- complessa (con puntatori che puntano ad altri dati, che a loro volta possono
- essere puntatori ad altri dati) si deve copiare non solo il contenuto della
+\itindex{deep~copy}\textit{deep copy}.\footnote{si chiama così quella tecnica
+ per cui, quando si deve copiare il contenuto di una struttura complessa (con
+ puntatori che puntano ad altri dati, che a loro volta possono essere
+ puntatori ad altri dati) si deve copiare non solo il contenuto della
struttura, ma eseguire una scansione per risolvere anche tutti i puntatori
contenuti in essa (e così via se vi sono altre sottostrutture con altri
puntatori) e copiare anche i dati da questi referenziati.}
\param{buf} e \param{buflen}.
Gli ultimi due argomenti vengono utilizzati per avere indietro i risultati
-come \index{\textit{value~result~argument}}\textit{value result argument}, si
-deve specificare l'indirizzo della variabile su cui la funzione dovrà salvare
-il codice di errore con \param{h\_errnop} e quello su cui dovrà salvare il
+come \itindex{value~result~argument}\textit{value result argument}, si deve
+specificare l'indirizzo della variabile su cui la funzione dovrà salvare il
+codice di errore con \param{h\_errnop} e quello su cui dovrà salvare il
puntatore che si userà per accedere i dati con \param{result}.
In caso di successo entrambe le funzioni restituiscono un valore nullo,
sistema è associata ad un indirizzo di tale tipo.\\
\const{AI\_DEFAULT} & il valore di default, è equivalente alla
combinazione di \const{AI\_ADDRCONFIG} e di
- \const{AI\_V4MAPPED)}.\\
+ \const{AI\_V4MAPPED}.\\
\hline
\end{tabular}
\caption{Valori possibili per i bit dell'argomento \param{flags} della
risoluzioni sui nomi dei servizi indipendentemente dal protocollo (ad esempio
TCP o UDP) che questi possono utilizzare.
+Come ultimo argomento in \param{res} deve essere passato un puntatore ad una
+variabile (di tipo puntatore ad una struttura \struct{addrinfo}) che verrà
+utilizzata dalla funzione per riportare (come \itindex{value~result~argument}
+\textit{value result argument}) i propri risultati. La funzione infatti è
+rientrante, ed alloca autonomamente tutta la memoria necessaria in cui
+verranno riportati i risultati della risoluzione. La funzione scriverà
+all'indirizzo puntato da \param{res} il puntatore iniziale ad una
+\itindex{linked~list}\textit{linked list} di strutture di tipo
+\struct{addrinfo} contenenti tutte le informazioni ottenute.
+
\begin{figure}[!htb]
\footnotesize \centering
\begin{minipage}[c]{15cm}
\label{fig:sock_addrinfo_struct}
\end{figure}
-La struttura \struct{addrinfo}, la cui definizione\footnote{la definizione è
- ripresa direttamente dal file \texttt{netdb.h} in questa struttura viene
- dichiarata, la pagina di manuale riporta \type{size\_t} come tipo di dato
- per il campo \var{ai\_addrlen}, qui viene usata quanto previsto dallo
- standard POSIX, in cui viene utilizzato \type{socklen\_t}; i due tipi di
- dati sono comunque equivalenti.} è riportata in
+Come illustrato la struttura \struct{addrinfo}, la cui definizione\footnote{la
+ definizione è ripresa direttamente dal file \texttt{netdb.h} in questa
+ struttura viene dichiarata, la pagina di manuale riporta \type{size\_t} come
+ tipo di dato per il campo \var{ai\_addrlen}, qui viene usata quanto previsto
+ dallo standard POSIX, in cui viene utilizzato \type{socklen\_t}; i due tipi
+ di dati sono comunque equivalenti.} è riportata in
fig.~\ref{fig:sock_addrinfo_struct}, viene usata sia in ingresso, per passare
dei valori di controllo alla funzione, che in uscita, per ricevere i
risultati. Il primo campo, \var{ai\_flags}, è una maschera binaria di bit che
famiglia di indirizzi, il tipo di socket e il protocollo, in ingresso vengono
usati per impostare una selezione (impostandone il valore nella struttura
puntata da \param{hints}), mentre in uscita indicano il tipo di risultato
-contenuto nella struttura.
+contenuto nella struttura.
Tutti i campi seguenti vengono usati soltanto in uscita; il campo
\var{ai\_addrlen} indica la dimensione della struttura degli indirizzi
\label{tab:ai_flags_values}
\end{table}
-Come ultimo argomento di \func{getaddrinfo} deve essere passato un puntatore
-ad una variabile (di tipo puntatore ad una struttura \struct{addrinfo}) che
-verrà utilizzata dalla funzione per riportare (come \textit{value result
- argument}) i propri risultati. La funzione infatti è rientrante, ed alloca
-autonomamente tutta la memoria necessaria in cui verranno riportati i
-risultati della risoluzione. La funzione scriverà in \param{res} il puntatore
-iniziale ad una \index{\textit{linked~list}}\textit{linked list} di strutture
-di tipo \struct{addrinfo} contenenti tutte le informazioni ottenute.
-
La funzione restituisce un valore nullo in caso di successo, o un codice in
caso di errore. I valori usati come codice di errore sono riportati in
tab.~\ref{tab:addrinfo_error_code}; dato che la funzione utilizza altre
\begin{figure}[!htb]
\centering
\includegraphics[width=10cm]{img/addrinfo_list}
- \caption{La \index{\textit{linked~list}}\textit{linked list} delle strutture
+ \caption{La \itindex{linked~list}\textit{linked list} delle strutture
\struct{addrinfo} restituite da \func{getaddrinfo}.}
\label{fig:sock_addrinfo_list}
\end{figure}
Come primo esempio di uso di \func{getaddrinfo} vediamo un programma
-elementare di interrogazione del \index{\textit{resolver}}\textit{resolver}
-basato questa funzione, il cui corpo principale è riportato in
+elementare di interrogazione del \itindex{resolver}\textit{resolver} basato
+questa funzione, il cui corpo principale è riportato in
fig.~\ref{fig:mygetaddr_example}. Il codice completo del programma, compresa
la gestione delle opzioni in cui è gestita l'eventuale inizializzazione
dell'argomento \var{hints} per restringere le ricerche su protocolli, tipi di
\end{Verbatim}
%$
-Una volta estratti i risultati dalla
-\index{\textit{linked~list}}\textit{linked list} puntata da \param{res} se
-questa non viene più utilizzata si dovrà avere cura di disallocare
-opportunamente tutta la memoria, per questo viene fornita l'apposita funzione
-\funcd{freeaddrinfo}, il cui prototipo è:
+Una volta estratti i risultati dalla \itindex{linked~list}\textit{linked list}
+puntata da \param{res} se questa non viene più utilizzata si dovrà avere cura
+di disallocare opportunamente tutta la memoria, per questo viene fornita
+l'apposita funzione \funcd{freeaddrinfo}, il cui prototipo è:
\begin{functions}
\headdecl{netdb.h}
Si tenga presente infine che se si copiano i risultati da una delle strutture
\struct{addrinfo} restituite nella lista indicizzata da \param{res}, occorre
-avere cura di eseguire una \index{\textit{deep~copy}}\textit{deep copy} in cui
+avere cura di eseguire una \itindex{deep~copy}\textit{deep copy} in cui
si copiano anche tutti i dati presenti agli indirizzi contenuti nella
struttura \struct{addrinfo}, perché una volta disallocati i dati con
\func{freeaddrinfo} questi non sarebbero più disponibili.
per entrambe le funzioni. In questo caso \param{optval} viene usato per
ricevere le informazioni ed indica l'indirizzo a cui andranno scritti i dati
letti dal socket, infine \param{optlen} diventa un puntatore ad una variabile
-che viene usata come \textit{value result argument} per indicare, prima della
-chiamata della funzione, la lunghezza del buffer allocato per \param{optval} e
-per ricevere indietro, dopo la chiamata della funzione, la dimensione
-effettiva dei dati scritti su di esso. Se la dimenzione del buffer allocato
-per \param{optval} non è sufficiente si avrà un errore.
+che viene usata come \itindex{value~result~argument}\textit{value result
+ argument} per indicare, prima della chiamata della funzione, la lunghezza
+del buffer allocato per \param{optval} e per ricevere indietro, dopo la
+chiamata della funzione, la dimensione effettiva dei dati scritti su di esso.
+Se la dimenzione del buffer allocato per \param{optval} non è sufficiente si
+avrà un errore.
approfondimento sul significato delle opzioni generiche più importanti.
-\index{\texttt{SO\_KEEPALIVE} (costante)|(}
+\index{costante!{\tt SO\_KEEPALIVE}|(}
\subsubsection{L'opzione \const{SO\_KEEPALIVE}}
La prima opzione da approfondire è \const{SO\_KEEPALIVE} che permette di
connessione verrà pertanto eseguita o meno la sezione (\texttt{\small 14--17})
che esegue l'impostazione di \const{SO\_KEEPALIVE} sul socket connesso,
attivando il relativo comportamento.
-\index{\texttt{SO\_KEEPALIVE} (costante)|)}
+\index{costante!{\tt SO\_KEEPALIVE}|)}
-\index{\texttt{SO\_REUSEADDR} (costante)|(}
+\index{costante!{\tt SO\_REUSEADDR}|(}
\subsubsection{L'opzione \const{SO\_REUSEADDR}}
La seconda opzione da approfondire è \const{SO\_REUSEADDR}, che consente di
primo programma a consentirlo, avendo usato fin dall'inizio
\const{SO\_REUSEADDR}.}
-\index{\texttt{SO\_REUSEADDR} (costante)|)}
+\index{costante!{\tt SO\_REUSEADDR}|)}
-
-\index{\texttt{SO\_LINGER} (costante)|(}
+\index{costante!{\tt SO\_LINGER}|(}
\subsubsection{L'opzione \const{SO\_LINGER}}
La terza opzione da approfondire è \const{SO\_LINGER}; essa, come il nome
completamento della trasmissione dei dati sul buffer.} pari al valore
specificato in \var{l\_linger}.
-
-
-\index{\texttt{SO\_LINGER} (costante)|)}
+\index{costante!{\tt SO\_LINGER}|)}
può essere un file (di tipo socket) nel filesystem o una stringa univoca
(mantenuta in uno spazio di nomi astratto). Nel primo caso l'indirizzo viene
specificato come una stringa (terminata da uno zero) corrispondente al
-\index{\textit{pathname}}\textit{pathname} del file; nel secondo invece
+\itindex{pathname}\textit{pathname} del file; nel secondo invece
\var{sun\_path} inizia con uno zero e vengono usati come nome i restanti byte
come stringa, senza terminazione.
a pacchetto, di tipo \const{SOCK\_DGRAM}; l'argomento \param{protocol} di
\func{socket} deve essere nullo. È altresì possibile usare i socket raw
specificando un tipo \const{SOCK\_RAW}, nel qual caso l'unico valore valido
-per \param{protocol} è \func{ATPROTO\_DDP}.
+per \param{protocol} è \const{ATPROTO\_DDP}.
Gli indirizzi AppleTalk devono essere specificati tramite una struttura
\struct{sockaddr\_atalk}, la cui definizione è riportata in
\subsection{La \textit{endianess}}
\label{sec:sock_endianess}
-\index{\textit{endianess}|(}
+\itindbeg{endianess}
La rappresentazione di un numero binario in un computer può essere fatta in
due modi, chiamati rispettivamente \textit{big endian} e \textit{little
endian} a seconda di come i singoli bit vengono aggregati per formare le
significativo (cioè, per quanto visto in fig.~\ref{fig:sock_endianess}, che sia
\textit{little endian}). Infine la funzione restituisce (\texttt{\small 12})
il valore del confonto delle due variabili.
-
-\index{\textit{endianess}|)}
+\itindend{endianess}
\subsection{Le funzioni per il riordinamento}
\label{sec:sock_func_ord}
-Il problema connesso all'endianess\index{\textit{endianess}} è che quando si
-passano dei dati da un tipo di architettura all'altra i dati vengono
-interpretati in maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci
-si ritroverà con i due byte in cui è suddiviso scambiati di posto. Per questo
-motivo si usano delle funzioni di conversione che servono a tener conto
-automaticamente della possibile differenza fra l'ordinamento usato sul
-computer e quello che viene usato nelle trasmissione sulla rete; queste
-funzioni sono \funcd{htonl}, \funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i
-rispettivi prototipi sono:
+Il problema connesso all'endianess\itindex{endianess} è che quando si passano
+dei dati da un tipo di architettura all'altra i dati vengono interpretati in
+maniera diversa, e ad esempio nel caso dell'intero a 16 bit ci si ritroverà
+con i due byte in cui è suddiviso scambiati di posto. Per questo motivo si
+usano delle funzioni di conversione che servono a tener conto automaticamente
+della possibile differenza fra l'ordinamento usato sul computer e quello che
+viene usato nelle trasmissione sulla rete; queste funzioni sono \funcd{htonl},
+\funcd{htons}, \funcd{ntohl} e \funcd{ntohs} ed i rispettivi prototipi sono:
\begin{functions}
\headdecl{netinet/in.h}
\funcdecl{unsigned long int htonl(unsigned long int hostlong)}
\const{LINK\_MAX} &8 & numero massimo di link a un file\\
\const{NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\
\const{PATH\_MAX}& 256 & lunghezza in byte di un
- \index{\textit{pathname}}\textit{pathname}.\\
+ \itindex{pathname}\textit{pathname}.\\
\const{PIPE\_BUF}&4096 & byte scrivibili atomicamente in una pipe
(vedi sez.~\ref{sec:ipc_pipes}).\\
\const{MAX\_CANON}&255 & dimensione di una riga di terminale in modo
\const{\_POSIX\_LINK\_MAX} &8 & numero massimo di link a un file.\\
\const{\_POSIX\_NAME\_MAX}& 14 & lunghezza in byte di un nome di file. \\
\const{\_POSIX\_PATH\_MAX}& 256 & lunghezza in byte di un
- \index{\textit{pathname}}\textit{pathname}.\\
+ \itindex{pathname}\textit{pathname}.\\
\const{\_POSIX\_PIPE\_BUF}& 512 & byte scrivibili atomicamente in una
pipe.\\
\const{\_POSIX\_MAX\_CANON}&255 & dimensione di una riga di
a quale file si fa riferimento, dato che il valore del limite cercato può
variare a seconda del filesystem. Una seconda versione della funzione,
\funcd{fpathconf}, opera su un file descriptor invece che su un
-\index{\textit{pathname}}\textit{pathname}. Il suo prototipo è:
+\itindex{pathname}\textit{pathname}. Il suo prototipo è:
\begin{prototype}{unistd.h}{long fpathconf(int fd, int name)}
Restituisce il valore del parametro \param{name} per il file \param{fd}.
\bodydesc{È identica a \func{pathconf} solo che utilizza un file descriptor
- invece di un \index{\textit{pathname}}\textit{pathname}; pertanto gli
- errori restituiti cambiano di conseguenza.}
+ invece di un \itindex{pathname}\textit{pathname}; pertanto gli errori
+ restituiti cambiano di conseguenza.}
\end{prototype}
\noindent ed il suo comportamento è identico a quello di \func{pathconf}.
occorrerà includere anche i file \file{linux/unistd.h} e
\file{linux/sysctl.h}.} per accedere ad uno di essi occorre specificare un
cammino attraverso i vari nodi dell'albero, in maniera analoga a come avviene
-per la risoluzione di un \index{\textit{pathname}}\textit{pathname} (da cui
-l'uso alternativo del filesystem \file{/proc}, che vedremo dopo).
+per la risoluzione di un \itindex{pathname}\textit{pathname} (da cui l'uso
+alternativo del filesystem \file{/proc}, che vedremo dopo).
Ciascun nodo dell'albero è identificato da un valore intero, ed il cammino che
arriva ad identificare un parametro specifico è passato alla funzione
In particolare l'albero dei valori di \func{sysctl} viene presentato in forma
di file nella directory \file{/proc/sys}, cosicché è possibile accedervi
-specificando un \index{\textit{pathname}}\textit{pathname} e leggendo e
-scrivendo sul file corrispondente al parametro scelto. Il kernel si occupa di
-generare al volo il contenuto ed i nomi dei file corrispondenti, e questo ha
-il grande vantaggio di rendere accessibili i vari parametri a qualunque
-comando di shell e di permettere la navigazione dell'albero dei valori.
+specificando un \itindex{pathname}\textit{pathname} e leggendo e scrivendo sul
+file corrispondente al parametro scelto. Il kernel si occupa di generare al
+volo il contenuto ed i nomi dei file corrispondenti, e questo ha il grande
+vantaggio di rendere accessibili i vari parametri a qualunque comando di shell
+e di permettere la navigazione dell'albero dei valori.
Alcune delle corrispondenze dei file presenti in \file{/proc/sys} con i valori
di \func{sysctl} sono riportate nei commenti del codice che può essere trovato
\textit{mount point} o di spostarlo quando \param{target} non è un
\textit{mount point} o è \file{/}.
\item[\errcode{EACCES}] non si ha il permesso di accesso su uno dei
- componenti del \index{\textit{pathname}}\textit{pathname}, o si è cercato
+ componenti del \itindex{pathname}\textit{pathname}, o si è cercato
di montare un filesystem disponibile in sola lettura senza averlo
specificato o il device \param{source} è su un filesystem montato con
l'opzione \const{MS\_NODEV}.
informazioni degli utenti e dei gruppi per insiemi di macchine, in modo da
mantenere coerenti i dati, ha portato anche alla necessità di poter recuperare
e memorizzare dette informazioni su supporti diversi, introducendo il sistema
-del \index{\textit{Name~Service~Switch}}\textit{Name Service Switch} che
-tratteremo brevemente più avanti (in sez.~\ref{sec:sock_resolver}) dato che la
-maggior parte delle sua applicazioni sono relative alla risoluzioni di nomi di
-rete.
+del \itindex{Name~Service~Switch}\textit{Name Service Switch} che tratteremo
+brevemente più avanti (in sez.~\ref{sec:sock_resolver}) dato che la maggior
+parte delle sua applicazioni sono relative alla risoluzioni di nomi di rete.
In questo paragrafo ci limiteremo comunque a trattere le funzioni classiche
per la lettura delle informazioni relative a utenti e gruppi tralasciando
Le funzioni viste finora sono in grado di leggere le informazioni sia
direttamente dal file delle password in \file{/etc/passwd} che tramite il
-sistema del \index{\textit{Name~Service~Switch}}\textit{Name Service Switch} e
+sistema del \itindex{Name~Service~Switch}\textit{Name Service Switch} e
sono completamente generiche. Si noti però che non c'è una funzione che
permetta di impostare direttamente una password.\footnote{in realtà questo può
essere fatto ricorrendo a PAM, ma questo è un altro discorso.} Dato che
Gli altri tre campi servono a quantificare l'uso della memoria
virtuale\index{memoria~virtuale} e corrispondono rispettivamente al numero di
-\textit{page fault}\index{\textit{page~fault}} (vedi
-sez.~\ref{sec:proc_mem_gen}) avvenuti senza richiedere I/O su disco (i
-cosiddetti \textit{minor page fault}), a quelli che invece han richiesto I/O
-su disco (detti invece \textit{major page fault}) ed al numero di volte che il
-processo è stato completamente tolto dalla memoria per essere inserito nello
-swap.
+\textit{page fault}\itindex{page~fault} (vedi sez.~\ref{sec:proc_mem_gen})
+avvenuti senza richiedere I/O su disco (i cosiddetti \textit{minor page
+ fault}), a quelli che invece han richiesto I/O su disco (detti invece
+\textit{major page fault}) ed al numero di volte che il processo è stato
+completamente tolto dalla memoria per essere inserito nello swap.
In genere includere esplicitamente \file{<sys/time.h>} non è più strettamente
necessario, ma aumenta la portabilità, e serve comunque quando, come nella
\end{prototype}
La funzione restituisce in ciascun elemento di \param{loadavg} il numero medio
-di processi attivi sulla coda dello scheduler\index{\textit{scheduler}},
-calcolato su un diverso intervalli di tempo. Il numero di intervalli che si
-vogliono leggere è specificato da \param{nelem}, dato che nel caso di Linux il
-carico viene valutato solo su tre intervalli (corrispondenti a 1, 5 e 15
-minuti), questo è anche il massimo valore che può essere assegnato a questo
-argomento.
+di processi attivi sulla coda dello scheduler\itindex{scheduler}, calcolato su
+un diverso intervalli di tempo. Il numero di intervalli che si vogliono
+leggere è specificato da \param{nelem}, dato che nel caso di Linux il carico
+viene valutato solo su tre intervalli (corrispondenti a 1, 5 e 15 minuti),
+questo è anche il massimo valore che può essere assegnato a questo argomento.
\subsection{La creazione della connessione: il \textit{three way handshake}}
\label{sec:TCP_conn_cre}
-\index{\textit{three~way~handshake}|(}
+\itindbeg{three~way~handshake}
Il processo che porta a creare una connessione TCP è chiamato \textit{three
way handshake}; la successione tipica degli eventi (e dei
\textsl{segmenti}\footnote{Si ricordi che il segmento è l'unità elementare di
SYN consuma un byte, nel \textit{three way handshake} il numero di acknowledge
è sempre pari al numero di sequenza iniziale incrementato di uno; lo stesso
varrà anche (vedi fig.~\ref{fig:TCP_close}) per l'acknowledgement di un FIN.
-\index{\textit{three~way~handshake}|)}
+
+\itindend{three~way~handshake}
\subsection{Le opzioni TCP.}
\const{INADDR\_ANY}, anche se, essendo questo nullo, il riordinamento è
inutile. Si tenga presente comunque che tutte le costanti \val{INADDR\_}
(riportate in tab.~\ref{tab:TCP_ipv4_addr}) sono definite secondo
-l'\textit{endianess}\index{\textit{endianess}} della macchina, ed anche se
+l'\textit{endianess}\itindex{endianess} della macchina, ed anche se
esse possono essere invarianti rispetto all'ordinamento dei bit, è comunque
buona norma usare sempre la funzione \func{htonl}.
limiterà ad impostare l'indirizzo dal quale e verso il quale saranno inviati
e ricevuti i pacchetti, mentre per socket di tipo \const{SOCK\_STREAM} o
\const{SOCK\_SEQPACKET}, essa attiverà la procedura di avvio (nel caso del
- TCP il \index{\textit{three~way~handshake}}\textit{three way handshake})
- della connessione.} il prototipo della funzione è il seguente:
+ TCP il \itindex{three~way~handshake}\textit{three way handshake}) della
+ connessione.} il prototipo della funzione è il seguente:
\begin{prototype}{sys/socket.h}
{int connect(int sockfd, const struct sockaddr *servaddr, socklen\_t
addrlen)}
in sez.~\ref{sec:sock_addr_func}.
Nel caso di socket TCP la funzione \func{connect} avvia il
-\index{\textit{three~way~handshake}}\textit{three way handshake}, e ritorna
+\itindex{three~way~handshake}\textit{three way handshake}, e ritorna
solo quando la connessione è stabilita o si è verificato un errore. Le
possibili cause di errore sono molteplici (ed i relativi codici riportati
sopra), quelle che però dipendono dalla situazione della rete e non da errori
\begin{enumerate}
\item La coda delle connessioni incomplete (\textit{incomplete connection
queue} che contiene un riferimento per ciascun socket per il quale è
- arrivato un SYN ma il \index{\textit{three~way~handshake}}\textit{three way
+ arrivato un SYN ma il \itindex{three~way~handshake}\textit{three way
handshake} non si è ancora concluso. Questi socket sono tutti nello stato
\texttt{SYN\_RECV}.
\item La coda delle connessioni complete (\textit{complete connection queue}
delle connessioni incomplete, e poi risponde con il SYN$+$ACK. La voce resterà
nella coda delle connessioni incomplete fino al ricevimento dell'ACK dal
client o fino ad un timeout. Nel caso di completamento del
-\index{\textit{three~way~handshake}}\textit{three way handshake} la voce viene
+\itindex{three~way~handshake}\textit{three way handshake} la voce viene
spostata nella coda delle connessioni complete. Quando il processo chiama la
funzione \func{accept} (vedi sez.~\ref{sec:TCP_func_accept}) la prima voce
nella coda delle connessioni complete è passata al programma, o, se la coda è
server è occupato fra chiamate successive alla \func{accept} (per cui la coda
più occupata sarebbe quella delle connessioni completate), ma piuttosto quello
di gestire la presenza di un gran numero di SYN in attesa di concludere il
-\textit{three way handshake}\index{\textit{three~way~handshake}}.
+\textit{three way handshake}\itindex{three~way~handshake}.
Infine va messo in evidenza che, nel caso di socket TCP, quando un SYN arriva
con tutte le code piene, il pacchetto deve essere ignorato. Questo perché la
\label{sec:TCP_func_accept}
La funzione \funcd{accept} è chiamata da un server per gestire la connessione
-una volta che sia stato completato il \textit{three way
- handshake},\footnote{la funzione è comunque generica ed è utilizzabile su
- socket di tipo \const{SOCK\_STREAM}, \const{SOCK\_SEQPACKET} e
- \const{SOCK\_RDM}.} la funzione restituisce un nuovo socket descriptor su
+una volta che sia stato completato il \itindex{three~way~handshake}
+\textit{three way handshake},\footnote{la funzione è comunque generica ed è
+ utilizzabile su socket di tipo \const{SOCK\_STREAM}, \const{SOCK\_SEQPACKET}
+ e \const{SOCK\_RDM}.} la funzione restituisce un nuovo socket descriptor su
cui si potrà operare per effettuare la comunicazione. Se non ci sono
connessioni completate il processo viene messo in attesa. Il prototipo della
funzione è il seguente:
interfaccia locale.
A questo punto si può lanciare il client, esso chiamerà \func{socket} e
-\func{connect}; una volta completato il \textit{three way handshake} la
-connessione è stabilita; la \func{connect} ritornerà nel client\footnote{si
- noti che è sempre la \func{connect} del client a ritornare per prima, in
- quanto questo avviene alla ricezione del secondo segmento (l'ACK del server)
- del \textit{three way handshake}, la \func{accept} del server ritorna solo
- dopo un altro mezzo RTT quando il terzo segmento (l'ACK del client) viene
- ricevuto.} e la \func{accept} nel server, ed usando di nuovo \cmd{netstat}
-otterremmo che:
+\func{connect}; una volta completato il \itindex{three~way~handshake}
+\textit{three way handshake} la connessione è stabilita; la \func{connect}
+ritornerà nel client\footnote{si noti che è sempre la \func{connect} del
+ client a ritornare per prima, in quanto questo avviene alla ricezione del
+ secondo segmento (l'ACK del server) del \textit{three way handshake}, la
+ \func{accept} del server ritorna solo dopo un altro mezzo RTT quando il
+ terzo segmento (l'ACK del client) viene ricevuto.} e la \func{accept} nel
+server, ed usando di nuovo \cmd{netstat} otterremmo che:
\begin{verbatim}
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State
con dei server molto occupati. In tal caso, con una struttura del server
simile a quella del nostro esempio, in cui la gestione delle singole
connessioni è demandata a processi figli, può accadere che il \textit{three
- way handshake}\index{\textit{three~way~handshake}} venga completato e la
-relativa connessione abortita subito dopo, prima che il padre, per via del
-carico della macchina, abbia fatto in tempo ad eseguire la chiamata ad
-\func{accept}. Di nuovo si ha una situazione analoga a quella illustrata in
+ way handshake}\itindex{three~way~handshake} venga completato e la relativa
+connessione abortita subito dopo, prima che il padre, per via del carico della
+macchina, abbia fatto in tempo ad eseguire la chiamata ad \func{accept}. Di
+nuovo si ha una situazione analoga a quella illustrata in
fig.~\ref{fig:TCP_early_abort}, in cui la connessione viene stabilita, ma
subito dopo si ha una condizione di errore che la chiude prima che essa sia
stata accettata dal programma.
Le prime tre righe vengono prodotte al momento in cui lanciamo il nostro
client, e corrispondono ai tre pacchetti del
-\index{\textit{three~way~handshake}}\textit{three way handshake}. L'output
-del comando riporta anche i numeri di sequenza iniziali, mentre la lettera
+\itindex{three~way~handshake}\textit{three way handshake}. L'output del
+comando riporta anche i numeri di sequenza iniziali, mentre la lettera
\texttt{S} indica che per quel pacchetto si aveva il SYN flag attivo. Si noti
come a partire dal secondo pacchetto sia sempre attivo il campo \texttt{ack},
seguito dal numero di sequenza per il quale si da il ricevuto; quest'ultimo, a
porta un SYN, cui il client risponde con un il terzo pacchetto di ricevuto.
Ritorniamo allora alla nostra sessione con il servizio echo: dopo le tre righe
-del \textit{three way handshake}\index{\textit{three~way~handshake}} non
-avremo nulla fin tanto che non scriveremo una prima riga sul client; al
-momento in cui facciamo questo si genera una sequenza di altri quattro
-pacchetti. Il primo, dal client al server, contraddistinto da una lettera
-\texttt{P} che significa che il flag PSH è impostato, contiene la nostra riga
-(che è appunto di 11 caratteri), e ad esso il server risponde immediatamente
-con un pacchetto vuoto di ricevuto. Poi tocca al server riscrivere indietro
-quanto gli è stato inviato, per cui sarà lui a mandare indietro un terzo
-pacchetto con lo stesso contenuto appena ricevuto, e a sua volta riceverà dal
-client un ACK nel quarto pacchetto. Questo causerà la ricezione dell'eco nel
-client che lo stamperà a video.
+del \textit{three way handshake}\itindex{three~way~handshake} non avremo nulla
+fin tanto che non scriveremo una prima riga sul client; al momento in cui
+facciamo questo si genera una sequenza di altri quattro pacchetti. Il primo,
+dal client al server, contraddistinto da una lettera \texttt{P} che significa
+che il flag PSH è impostato, contiene la nostra riga (che è appunto di 11
+caratteri), e ad esso il server risponde immediatamente con un pacchetto vuoto
+di ricevuto. Poi tocca al server riscrivere indietro quanto gli è stato
+inviato, per cui sarà lui a mandare indietro un terzo pacchetto con lo stesso
+contenuto appena ricevuto, e a sua volta riceverà dal client un ACK nel quarto
+pacchetto. Questo causerà la ricezione dell'eco nel client che lo stamperà a
+video.
A questo punto noi procediamo ad interrompere l'esecuzione del server con un
\texttt{C-c} (cioè con l'invio di \const{SIGTERM}): nel momento in cui