Una lunga serie di modifiche per tenere conto della riorganizzazione della
[gapil.git] / fileadv.tex
index 0c53338765e9b18bd0c8c3d3c39ce3d905416859..2d000d8baa659e3a7e35f4bae109e3203262625b 100644 (file)
@@ -1,6 +1,6 @@
 %% fileadv.tex
 %%
-%% Copyright (C) 2000-2002 Simone Piccardi.  Permission is granted to
+%% Copyright (C) 2000-2003 Simone Piccardi.  Permission is granted to
 %% copy, distribute and/or modify this document under the terms of the GNU Free
 %% Documentation License, Version 1.1 or any later version published by the
 %% Free Software Foundation; with the Invariant Sections being "Prefazione",
 \label{cha:file_advanced}
 
 In questo capitolo affronteremo le tematiche relative alla gestione avanzata
-dei file, che non sono state trattate in \capref{cha:file_unix_interface},
-dove ci si è limitati ad una panoramica delle funzioni base. In particolare
-tratteremo delle funzioni di input/output avanzato e del \textit{file
-  locking}.
+dei file. In particolare tratteremo delle funzioni di input/output avanzato,
+che permettono una gestione più sofisticata dell'I/O su file, a partire da
+quelle che permettono di gestire l'accesso contemporaneo a più file, per
+concludere con la gestione dell'I/O mappato in memoria. Dedicheremo poi la
+fine del capitolo alle problematiche del \textit{file locking}.
 
 
-\section{Le funzioni di I/O avanzato}
-\label{sec:file_advanced_io}
+\section{L'\textit{I/O multiplexing}}
+\label{sec:file_multiplexing}
 
-In questa sezione esamineremo le funzioni che permettono una gestione più
-sofisticata dell'I/O su file, a partire da quelle che permettono di gestire
-l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O
-mappato in memoria.
+Uno dei problemi che si presentano quando si deve operare contemporaneamente
+su molti file usando le funzioni illustrate in
+\capref{cha:file_unix_interface} e \capref{cha:files_std_interface} è che si
+può essere bloccati nelle operazioni su un file mentre un altro potrebbe
+essere disponibile. L'\textit{I/O multiplexing} nasce risposta a questo
+problema. In questa sezione forniremo una introduzione a questa problematica
+ed analizzeremo le varie funzioni usate per implementare questa modalità di
+I/O.
 
 
-\subsection{La modalità di I/O \textsl{non-bloccante}}
+\subsection{La problematica dell'\textit{I/O multiplexing}}
 \label{sec:file_noblocking}
 
 Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
-\textit{fast} e \textit{slow} system call, che in certi casi le funzioni di
-I/O possono bloccarsi indefinitamente.\footnote{si ricordi però che questo può
-  accadere solo per le pipe, i socket ed alcuni file di dispositivo; sui file
-  normali le funzioni di lettura e scrittura ritornano sempre subito.}  Ad
-esempio le operazioni di lettura possono bloccarsi quando non ci sono dati
-disponibili sul descrittore su cui si sta operando.
+\textit{fast} e \textit{slow} system call,\index{system call lente} che in
+certi casi le funzioni di I/O possono bloccarsi indefinitamente.\footnote{si
+  ricordi però che questo può accadere solo per le pipe, i
+  socket\index{socket} ed alcuni file di dispositivo\index{file!di
+    dispositivo}; sui file normali le funzioni di lettura e scrittura
+  ritornano sempre subito.}  Ad esempio le operazioni di lettura possono
+bloccarsi quando non ci sono dati disponibili sul descrittore su cui si sta
+operando.
 
 Questo comportamento causa uno dei problemi più comuni che ci si trova ad
-affrontare nelle operazioni di I/O, che è quello che si verifica quando si
-devono eseguire operazioni che possono bloccarsi su più file descriptor:
-mentre si è bloccati su uno di essi su di un'altro potrebbero essere presenti
-dei dati; così che nel migliore dei casi si avrebbe una lettura ritardata
-inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un
-\textit{deadlock}.
+affrontare nelle operazioni di I/O, che si verifica quando si deve operare con
+più file descriptor eseguendo funzioni che possono bloccarsi senza che sia
+possibile prevedere quando questo può avvenire (il caso più classico è quello
+di un server in attesa di dati in ingresso da vari client). Quello che può
+accadere è di restare bloccati nell'eseguire una operazione su un file
+descriptor che non è ``\textsl{pronto}'', quando ce ne potrebbe essere
+un'altro disponibile. Questo comporta nel migliore dei casi una operazione
+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{deadlock}.
 
 Abbiamo già accennato in \secref{sec:file_open} che è possibile prevenire
-questo tipo di comportamento aprendo un file in modalità
-\textsl{non-bloccante}, attraverso l'uso del flag \const{O\_NONBLOCK} nella
-chiamata di \func{open}. In questo caso le funzioni di input/output che
-altrimenti si sarebbero bloccate ritornano immediatamente, restituendo
-l'errore \errcode{EAGAIN}.
+questo tipo di comportamento delle funzioni di I/O aprendo un file in quella
+che viene chiamata \textsl{modalità non-bloccante}, attraverso l'uso del flag
+\const{O\_NONBLOCK} nella chiamata di \func{open}. In questo caso le funzioni
+di input/output eseguite sul file che si sarebbero bloccate, ritornano
+immediatamente, 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{polling}, è estremamente inefficiente: si tiene
 costantemente impiegata la CPU solo per eseguire in continuazione delle system
-call che nella gran parte dei casi falliranno. Per evitare questo, come
-vedremo in \secref{sec:file_multiplexing}, è stata introdotta una nuova
-interfaccia di programmazione, che comporta comunque l'uso della modalità di
-I/O non bloccante.
-
-
-
-\subsection{L'I/O multiplexing}
-\label{sec:file_multiplexing}
-
-Per superare il problema di dover usare il \textit{polling}\index{polling} per
-controllare la possibilità di effettuare operazioni su un file aperto in
-modalità non bloccante, sia BSD che System V hanno introdotto delle nuove
-funzioni in grado di sospendere l'esecuzione di un processo in attesa che
-l'accesso diventi possibile.  Il primo ad introdurre questa modalità di
-operazione, chiamata usualmente \textit{I/O multiplexing}, è stato
-BSD,\footnote{la funzione è apparsa in BSD4.2 e standardizzata in BSD4.4, ma è
-  stata portata su tutti i sistemi che supportano i \textit{socket}, compreso
-  le varianti di System V.}  con la funzione \func{select}, il cui prototipo
-è:
+call che nella gran parte dei casi falliranno. 
+
+Per superare questo problema è stato introdotto il concetto di \textit{I/O
+  multiplexing}, una nuova modalità di operazioni che consenta di tenere sotto
+controllo più file descriptor in contemporanea, permettendo di bloccare un
+processo quando le operazioni volute non sono possibili, e di riprenderne
+l'esecuzione una volta che almeno una di quelle richieste sia disponibile, in
+modo da poterla eseguire con la sicurezza di non restare bloccati.
+
+Dato che, come abbiamo già accennato, per i normali file su disco non si ha
+mai un accesso bloccante, l'uso più comune delle funzioni che esamineremo nei
+prossimi paragrafi è per i server di rete, in cui esse vengono utilizzate per
+tenere sotto controllo dei socket; pertanto ritorneremo su di esse con
+ulteriori dettagli e qualche esempio in \secref{sec:TCP_sock_multiplexing}.
+
+
+\subsection{Le funzioni \func{select} e \func{pselect}}
+\label{sec:file_select}
+
+Il primo ad introdurre una interfaccia per l'\textit{I/O multiplexing} è stato
+BSD,\footnote{la funzione \func{select} è apparsa in BSD4.2 e standardizzata
+  in BSD4.4, ma è stata portata su tutti i sistemi che supportano i
+  \textit{socket}\index{socket}, compreso le varianti di System V.}  con la
+funzione \funcd{select}, il cui prototipo è:
 \begin{functions}
   \headdecl{sys/time.h}
   \headdecl{sys/types.h}
@@ -93,9 +109,10 @@ BSD,\footnote{la funzione 
     caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
   \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
+    degli insiemi.
   \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo.
+  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo o
+    un valore non valido per \param{timeout}.
   \end{errlist}
   ed inoltre \errval{ENOMEM}.
 }
@@ -110,8 +127,8 @@ degli insiemi specificati (\param{readfds}, \param{writefds} e
 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 \textit{signal set}, vedi
-\secref{sec:sig_sigset}, identifica un insieme di segnali). Per la
+file descriptor, in maniera analoga a come un \textit{signal set} (vedi
+\secref{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}
@@ -134,203 +151,303 @@ opportune macro di preprocessore:
 In genere un \textit{file descriptor set} può contenere fino ad un massimo di
 \const{FD\_SETSIZE} file descriptor.  Questo valore in origine corrispondeva
 al limite per il numero massimo di file aperti\footnote{ad esempio in Linux,
-  fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma
+  fino alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma da
 quando, come nelle versioni più recenti del kernel, non c'è più un limite
 massimo, esso indica le dimensioni massime dei numeri usati nei \textit{file
-  descriptor set}.
+  descriptor set}.\footnote{il suo valore, secondo lo standard POSIX
+  1003.1-2001, è definito in \file{sys/select.h}, ed è pari a 1024.} Si tenga
+presente che i \textit{file descriptor set} devono sempre essere inizializzati
+con \macro{FD\_ZERO}; passare a \func{select} un valore non inizializzato può
+dar luogo a comportamenti non prevedibili.
 
 La funzione richiede di specificare tre insiemi distinti di file descriptor;
 il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
-effettuare una lettura, il secondo, \param{writefds}, per verificare la
-possibilità effettuare una scrittura ed il terzo, \param{exceptfds}, per
-verificare l'esistenza di condizioni eccezionali (come i messaggi urgenti su
-un \textit{socket}\index{socket}, vedi \secref{sec:xxx_urgent}).
-
-La funzione inoltre richiede anche di specificare, tramite l'argomento
-\param{n}, un valore massimo del numero dei file descriptor usati
-nell'insieme; si può usare il già citato \const{FD\_SETSIZE}, oppure il numero
-più alto dei file descriptor usati nei tre insiemi, aumentato di uno.
-
-Infine l'argomento \param{timeout}, specifica un tempo massimo di
-attesa\footnote{il tempo è valutato come \textit{elapsed time}.} prima che la
-funzione ritorni; se impostato a \val{NULL} la funzione attende
-indefinitamente. Si può specificare anche un tempo nullo (cioè una \var{struct
-  timeval} con i campi impostati a zero), qualora si voglia semplicemente
-controllare lo stato corrente dei file descriptor.
-
-La funzione restituisce il totale dei file descriptor pronti nei tre insiemi,
-il valore zero indica sempre che si è raggiunto un timeout. Ciascuno dei tre
-insiemi viene sovrascritto per indicare quale file descriptor è pronto per le
-operazioni ad esso relative, in modo da poterlo controllare con la macro
-\const{FD\_ISSET}. In caso di errore la funzione restituisce -1 e gli insiemi
-non vengono toccati.
+effettuare una lettura,\footnote{per essere precisi la funzione ritornerà in
+  tutti i casi in cui la successiva esecuzione di \func{read} risulti non
+  bloccante, quindi anche in caso di \textit{end-of-file}.} il secondo,
+\param{writefds}, per verificare la possibilità effettuare una scrittura ed il
+terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i
+messaggi urgenti su un \textit{socket}\index{socket}, vedi
+\secref{sec:TCP_urgent_data}).
+
+Dato che in genere non si tengono mai sotto controllo fino a
+\const{FD\_SETSIZE} file contemporaneamente la funzione richiede di
+specificare qual'è il numero massimo dei file descriptor indicati nei tre
+insiemi precedenti. Questo viene fatto per efficienza, per evitare di passare
+e far controllare al kernel una quantità di memoria superiore a quella
+necessaria. Questo limite viene indicato tramite l'argomento \param{n}, che
+deve corrispondere al valore massimo aumentato di uno.\footnote{i file
+  descriptor infatti sono contati a partire da zero, ed il valore indica il
+  numero di quelli da tenere sotto controllo; dimenticarsi di aumentare di uno
+  il valore di \param{n} è un errore comune.}
+
+Infine l'argomento \param{timeout}, specifica un tempo massimo di attesa prima
+che la funzione ritorni; se impostato a \val{NULL} la funzione attende
+indefinitamente. Si può 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.
+
+La funzione restituisce il numero di file descriptor pronti,\footnote{questo è
+  il comportamento previsto dallo standard, ma la standardizzazione della
+  funzione è recente, ed esistono ancora alcune versioni di Unix che non si
+  comportano in questo modo.}  e ciascun insieme viene sovrascritto per
+indicare i file descriptor pronti per le operazioni ad esso relative, in modo
+da poterli controllare con \const{FD\_ISSET}.  Se invece si ha un timeout
+viene restituito un valore nullo e gli insiemi non vengono modificati.  In
+caso di errore la funzione restituisce -1, ed i valori dei tre insiemi sono
+indefiniti e non si può fare nessun affidamento sul loro contenuto.
 
 In Linux \func{select} modifica anche il valore di \param{timeout},
-impostandolo al tempo restante; questo è utile quando la funzione viene
-interrotta da un segnale, in tal caso infatti si ha un errore di
-\errcode{EINTR}, ed occorre rilanciare la funzione; in questo modo non è
-necessario ricalcolare tutte le volte il tempo rimanente.\footnote{questo può
-  causare problemi di portabilità sia quando si trasporta codice scritto su
-  Linux che legge questo valore, sia quando si usano programmi scritti per
-  altri sistemi che non dispongono di questa caratteristica e ricalcolano
-  \param{timeout} tutte le volte. In genere la caratteristica è disponibile
-  nei sistemi che derivano da System V e non disponibile per quelli che
-  derivano da BSD.}
-
-Come accennato l'interfaccia di \func{select} è una estensione di BSD; anche
-System V ha introdotto una sua interfaccia per gestire l'\textit{I/O
-  multiplexing}, basata sulla funzione \func{poll},\footnote{la funzione è
+impostandolo al tempo restante in caso di interruzione prematura; questo è
+utile quando la funzione viene interrotta da un segnale, in tal caso infatti
+si ha un errore di \errcode{EINTR}, ed occorre rilanciare la funzione; in
+questo modo non è necessario ricalcolare tutte le volte il tempo
+rimanente.\footnote{questo può causare problemi di portabilità sia quando si
+  trasporta codice scritto su Linux che legge questo valore, sia quando si
+  usano programmi scritti per altri sistemi che non dispongono di questa
+  caratteristica e ricalcolano \param{timeout} tutte le volte. In genere la
+  caratteristica è disponibile nei sistemi che derivano da System V e non
+  disponibile per quelli che derivano da BSD.}
+
+Uno dei problemi che si presentano con l'uso di \func{select} è che il suo
+comportamento dipende dal valore del file descriptor che si vuole tenere sotto
+controllo.  Infatti il kernel riceve con \param{n} un valore massimo per tale
+valore, e per capire quali sono i file descriptor da tenere sotto controllo
+dovrà effettuare una scansione su tutto l'intervallo, che può anche essere
+anche molto ampio anche se i file descriptor sono solo poche unità; tutto ciò
+ha ovviamente delle conseguenze ampiamente negative per le prestazioni.
+
+Inoltre c'è anche il problema che il numero massimo dei file che si possono
+tenere sotto controllo, la funzione è nata quando il kernel consentiva un
+numero massimo di 1024 file descriptor per processo, adesso che il numero può
+essere arbitario si viene a creare una dipendenza del tutto artificiale dalle
+dimensioni della struttura \type{fd\_set}, che può necessitare di essere
+estesa, con ulteriori perdite di prestazioni. 
+
+Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
+  multiplexing}, introdotto solo con le ultime revisioni dello standard (POSIX
+1003.1g-2000 e POSIX 1003.1-2001). La scelta è stata quella di seguire
+l'interfaccia creata da BSD, ma prevede che tutte le funzioni ad esso relative
+vengano dichiarate nell'header \file{sys/select.h}, che sostituisce i
+precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
+\funcd{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
+  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
+  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
+  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
+  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
+  \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
+  \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
+  maggiore di 600.} il cui prototipo è:
+\begin{prototype}{sys/select.h}
+  {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
+    struct timespec *timeout, sigset\_t *sigmask)}
+  
+  Attende che uno dei file descriptor degli insiemi specificati diventi
+  attivo.
+  
+  \bodydesc{La funzione in caso di successo restituisce il numero di file
+    descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
+    caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
+    degli insiemi.
+  \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo o
+    un valore non valido per \param{timeout}.
+  \end{errlist}
+  ed inoltre \errval{ENOMEM}.}
+\end{prototype}
+
+La funzione è sostanzialmente identica a \func{select}, solo che usa una
+struttura \struct{timespec} (vedi \figref{fig:sys_timeval_struct}) per
+indicare con maggiore precisione il timeout e non ne aggiorna il valore in
+caso di interruzione. Inoltre prende un argomento aggiuntivo \param{sigmask}
+che è il puntatore ad una maschera di segnali (si veda
+\secref{sec:sig_sigmask}). La maschera corrente viene sostituita da questa
+immediatamente prima di eseguire l'attesa, e ripristinata al ritorno della
+funzione.
+
+L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
+race condition\index{race condition} quando ci si deve porre in attesa sia di
+un segnale che di dati.\footnote{in Linux però non è stata ancora introdotta
+  la relativa system call, pertanto la funzione è implementata nelle
+  \acr{glibc} attraverso \func{select} e la possibilità di race condition
+  permane.} La tecnica classica è quella di utilizzare il gestore per
+impostare una variabile globale e controllare questa nel corpo principale del
+programma; abbiamo visto in \secref{sec:sig_example} come questo lasci spazio
+a possibili race condition, per cui diventa essenziale utilizzare
+\func{sigprocmask} per disabilitare la ricezione del segnale prima di eseguire
+il controllo e riabilitarlo dopo l'esecuzione delle relative operazioni, onde
+evitare l'arrivo di un segnale immediatamente dopo il controllo, che andrebbe
+perso.
+
+Nel nostro caso il problema si pone quando oltre al segnale si devono tenere
+sotto controllo anche dei file descriptor con \func{select}, in questo caso si
+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{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, e ribloccandolo non appena essa
+ritorna. In questo modo il precedente codice potrebbe essere essere modificato
+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{La funzione \func{poll}}
+\label{sec:file_poll}
+
+Nello sviluppo di System V, invece di utilizzare l'interfaccia di
+\func{select}, che è una estensione tipica di BSD, è stata introdotta un'altra
+interfaccia, basata sulla funzione \funcd{poll},\footnote{la funzione è
   prevista dallo standard XPG4, ed è stata introdotta in Linux come system
-  call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} il cui
-prototipo è:
+  call a partire dal kernel 2.1.23 ed inserita nelle \acr{libc} 5.4.28.} il
+cui prototipo è:
 \begin{prototype}{sys/poll.h}
   {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
-
-La funzione attente un cambiamento di stato per uno dei file descriptor
-specificati da \param{ufds}.
   
-\bodydesc{La funzione restituisce il numero di file descriptor con attività in
-  caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
-  restituito  -1 ed \var{errno} assumerà uno dei valori:
+  La funzione attende un cambiamento di stato per uno dei file descriptor
+  specificati da \param{ufds}.
+  
+  \bodydesc{La funzione restituisce il numero di file descriptor con attività
+    in caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
+    restituito -1 ed \var{errno} assumerà uno dei valori:
   \begin{errlist}
   \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
+    degli insiemi.
   \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+  \item[\errcode{EINVAL}] Il valore di \param{nfds} eccede il limite
+    \macro{RLIMIT\_NOFILE}.
   \end{errlist}
   ed inoltre \errval{EFAULT} e \errval{ENOMEM}.}
 \end{prototype}
 
-La funzione tiene sotto controllo un numero \param{ndfs} di file descriptor
-specificati attraverso un vettore di puntatori a strutture di tipo
-\type{pollfd}, la cui definizione è riportata in \figref{fig:file_pollfd}.
-Come \func{select} anche \func{poll} permette di interrompere l'attesa dopo un
-certo tempo, che va specificato attraverso \param{timeout} in numero di
-millisecondi (un valore negativo indica un'attesa indefinita).
+La funzione permette di tenere sotto controllo contemporaneamente \param{ndfs}
+file descriptor, specificati attraverso il puntatore \param{ufds} ad un
+vettore di strutture \struct{pollfd}.  Come con \func{select} si può
+interrompere l'attesa dopo un certo tempo, questo deve essere specificato con
+l'argomento \param{timeout} in numero di millisecondi: un valore negativo
+indica un'attesa indefinita, mentre un valore comporta il ritorno immediato (e
+può essere utilizzato per impiegare \func{poll} in modalità
+\textsl{non-bloccante}).
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct pollfd {
-        int fd;           /* file descriptor */
-        short events;     /* requested events */
-        short revents;    /* returned events */
-};
-    \end{lstlisting}
+    \includestruct{listati/pollfd.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \type{pollfd}, utilizzata per specificare le modalità
-    di controllo di un file descriptor alla funzione \func{poll}.}
+  \caption{La struttura \structd{pollfd}, utilizzata per specificare le
+    modalità di controllo di un file descriptor alla funzione \func{poll}.}
   \label{fig:file_pollfd}
 \end{figure}
 
-Per ciascun file da controllare deve essere opportunamente predisposta una
-struttura \type{pollfd}; nel campo \var{fd} deve essere specificato il file
-descriptor, mentre nel campo \var{events} il tipo di evento su cui si vuole
-attendere; quest'ultimo deve essere specificato come maschera binaria dei
-primi tre valori riportati in \tabref{tab:file_pollfd_flags} (gli altri
-vengono utilizzati solo per \var{revents} come valori in uscita).
+Per ciascun file da controllare deve essere inizializzata una struttura
+\struct{pollfd} nel vettore indicato dall'argomento \param{ufds}.  La
+struttura, la cui definizione è riportata in \figref{fig:file_pollfd}, prevede
+tre campi: in \var{fd} deve essere indicato il numero del file descriptor da
+controllare, in \var{events} deve essere specificata una maschera binaria di
+flag che indichino il tipo di evento che si vuole controllare, mentre in
+\var{revents} il kernel restituirà il relativo risultato.  Usando un valore
+negativo per \param{fd} la corrispondente struttura sarà ignorata da
+\func{poll}. Dato che i dati in ingresso sono del tutto indipendenti da quelli
+in uscita (che vengono restituiti in \var{revents}) non è necessario
+reinizializzare tutte le volte il valore delle strutture \struct{pollfd} a
+meno di non voler cambiare qualche condizione.
+
+Le costanti che definiscono i valori relativi ai bit usati nelle maschere
+binarie dei campi \var{events} e \var{revents} sono riportati in
+\tabref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
+suddivise in tre gruppi, nel primo gruppo si sono indicati i bit utilizzati
+per controllare l'attività in ingresso, nel secondo quelli per l'attività in
+uscita, mentre il terzo gruppo contiene dei valori che vengono utilizzati solo
+nel campo \var{revents} per notificare delle condizioni di errore. 
 
 \begin{table}[htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|l|c|l|}
+  \begin{tabular}[c]{|l|l|}
     \hline
-    \textbf{Flag} & \textbf{Valore} & \textbf{Significato} \\
+    \textbf{Flag}  & \textbf{Significato} \\
     \hline
     \hline
-    \const{POLLIN}    & 0x001 & È possibile la lettura immediata.\\
-    \const{POLLPRI}   & 0x002 & Sono presenti dati urgenti.\\
-    \const{POLLOUT}   & 0x004 & È possibile la scrittura immediata.\\
+    \const{POLLIN}    & È possibile la lettura.\\
+    \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\ 
+    \const{POLLRDBAND}& Sono disponibili in lettura dati prioritari. \\
+    \const{POLLPRI}   & È possibile la lettura di dati urgenti.\\
     \hline
-    \const{POLLERR}   & 0x008 & C'è una condizione di errore.\\
-    \const{POLLHUP}   & 0x010 & Si è verificato un hung-up.\\
-    \const{POLLNVAL}  & 0x020 & Il file descriptor non è aperto.\\
+    \const{POLLOUT}   & È possibile la scrittura immediata.\\
+    \const{POLLWRNORM}& È possibile la scrittura di dati normali.  \\ 
+    \const{POLLWRBAND}& È possibile la scrittura di dati prioritari. \\
     \hline
-    \const{POLLRDNORM}& 0x040 & Sono disponibili in lettura dati normali.\\ 
-    \const{POLLRDBAND}& 0x080 & Sono disponibili in lettura dati ad alta 
-                                priorità. \\
-    \const{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali.  \\ 
-    \const{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad 
-                                alta priorità. \\
-    \const{POLLMSG}   & 0x400 & Estensione propria di Linux.\\
+    \const{POLLERR}   & C'è una condizione di errore.\\
+    \const{POLLHUP}   & Si è verificato un hung-up.\\
+    \const{POLLNVAL}  & Il file descriptor non è aperto.\\
+    \hline
+    \const{POLLMSG}   & Definito per compatobilità con SysV.\\
     \hline    
   \end{tabular}
   \caption{Costanti per l'identificazione dei vari bit dei campi
-    \var{events} e \var{revents} di \type{pollfd}.}
+    \var{events} e \var{revents} di \struct{pollfd}.}
   \label{tab:file_pollfd_flags}
 \end{table}
 
-La funzione ritorna, restituendo il numero di file per i quali si è verificata
-una delle condizioni di attesa richieste od un errore. Lo stato dei file
-all'uscita della funzione viene restituito nel campo \var{revents} della
-relativa struttura \type{pollfd}, che viene impostato alla maschera binaria
-dei valori riportati in \tabref{tab:file_pollfd_flags}, ed oltre alle tre
-condizioni specificate tramite \var{events} può riportare anche l'occorrere di
-una condizione di errore.
-
-Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
-  multiplexing}, che è stata introdotto con le ultime revisioni dello standard
-(POSIX 1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni
-ad esso relative vengano dichiarate nell'header \file{sys/select.h}, che
-sostituisce i precedenti, ed aggiunge a \func{select} una nuova funzione
-\func{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
-  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
-  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
-  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
-  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
-  \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
-  \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
-  maggiore di 600.} il cui prototipo è:
-\begin{prototype}{sys/select.h}
-  {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
-    struct timespec *timeout, sigset\_t *sigmask)}
-  
-  Attende che uno dei file descriptor degli insiemi specificati diventi
-  attivo.
-  
-  \bodydesc{La funzione in caso di successo restituisce il numero di file
-    descriptor (anche nullo) che sono attivi, e -1 in caso di errore, nel qual
-    caso \var{errno} assumerà uno dei valori:
-  \begin{errlist}
-  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
-  \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\errcode{EINVAL}] Si è specificato per \param{n} un valore negativo.
-  \end{errlist}
-  ed inoltre \errval{ENOMEM}.}
-\end{prototype}
-
-La funzione è sostanzialmente identica a \func{select}, solo che usa una
-struttura \type{timespec} per indicare con maggiore precisione il timeout e
-non ne aggiorna il valore in caso di interruzione, inoltre prende un argomento
-aggiuntivo \param{sigmask} che è il puntatore ad una maschera di segnali (si
-veda \secref{sec:sig_sigmask}). La maschera corrente viene sostituita da
-questa immediatamente prima di eseguire l'attesa, e ripristinata al ritorno
-della funzione.
-
-L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
-race condition\footnote{in Linux però, non esistendo una system call apposita,
-  la funzione è implementata nelle \acr{glibc} usando \func{select}, e la
-  possibilità di una race condition resta.} quando si deve eseguire un test su
-una variabile assegnata da un manipolatore sulla base dell'occorrenza di un
-segnale per decidere se lanciare \func{select}. Fra il test e l'esecuzione è
-presente una finestra in cui potrebbe arrivare il segnale che non sarebbe
-rilevato; la race condition diventa superabile disabilitando il segnale prima
-del test e riabilitandolo poi grazie all'uso di \param{sigmask}.
-
-
-
-\subsection{L'I/O asincrono}
-\label{sec:file_asyncronous_io}
-
-Una modalità alternativa all'uso dell'\textit{I/O multiplexing} è quella di
-fare ricorso al cosiddetto \textsl{I/O asincrono}. Il concetto base
-dell'\textsl{I/O asincrono} è che le funzioni di I/O non attendono il
-completamento delle operazioni prima di ritornare, così che il processo non
-viene bloccato.  In questo modo diventa ad esempio possibile effettuare una
-richiesta preventiva di dati, in modo da poter effettuare in contemporanea le
-operazioni di calcolo e quelle di I/O.
+Il valore \const{POLLMSG} non viene utilizzato ed è definito solo per
+compatibilità con l'implementazione di SysV che usa gli
+\textit{stream};\footnote{essi sono una interfaccia specifica di SysV non
+  presente in Linux, e non hanno nulla a che fare con i file \textit{stream}
+  delle librerie standard del C.} è da questi che derivano i nomi di alcune
+costanti, in quanto per essi sono definite tre classi di dati:
+\textsl{normali}, \textit{prioritari} ed \textit{urgenti}.  In Linux la
+distinzione ha senso solo per i dati \textit{out-of-band} dei socket (vedi
+\secref{sec:TCP_urgent_data}), ma su questo e su come \func{poll} reagisce
+alle varie condizioni dei socket torneremo in \secref{sec:TCP_serv_poll}, dove
+vedremo anche un esempio del suo utilizzo. Si tenga conto comunque che le
+costanti relative ai diversi tipi di dati (come \macro{POLLRDNORM} e
+\macro{POLLRDBAND}) sono utilizzabili soltanto qualora si sia definito
+\macro{\_XOPEN\_SOURCE}.\footnote{e ci si ricordi di farlo sempre in testa al
+  file, definirla soltanto prima di includere \file{sys/poll.h} non è
+  sufficiente.}
+
+In caso di successo funzione ritorna restituendo il numero di file (un valore
+positivo) per i quali si è verificata una delle condizioni di attesa richieste
+o per i quali si è verificato un errore (nel qual caso vengono utilizzati i
+valori di \tabref{tab:file_pollfd_flags} esclusivi di \var{revents}). Un
+valore nullo indica che si è raggiunto il timeout, mentre un valore negativo
+indica un errore nella chiamata, il cui codice viene riportato al solito
+tramite \var{errno}.
+
+
+%\subsection{L'interfaccia di \textit{epoll}}
+%\label{sec:file_epoll}
+% placeholder ...
+
+%da fare
+
+\section{L'accesso \textsl{asincrono} ai file}
+\label{sec:file_asyncronous_access}
+
+Benché l'\textit{I/O multiplexing} sia stata la prima, e sia tutt'ora una fra
+le più diffuse modalità di gestire l'I/O in situazioni complesse in cui si
+debba operare su più file contemporaneamente, esistono altre modalità di
+gestione delle stesse problematiche. In particolare sono importanti in questo
+contesto le modalità di accesso ai file eseguibili in maniera
+\textsl{asincrona}, senza cioè che un processo debba bloccarsi, ed utilizzi
+invece un meccanismo di notifica asincrono, come un segnale, per rilevare la
+possibilità di eseguire le operazioni volute.
+
+
+\subsection{Operazioni asincrone sui file}
+\label{sec:file_asyncronous_operation}
 
 Abbiamo accennato in \secref{sec:file_open} che è possibile, attraverso l'uso
 del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e dei
@@ -338,41 +455,53 @@ del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e dei
   di Linux e BSD.} aprire un file in modalità asincrona, così come è possibile
 attivare in un secondo tempo questa modalità impostando questo flag attraverso
 l'uso di \func{fcntl} con il comando \const{F\_SETFL} (vedi
-\secref{sec:file_fcntl}).
-
-In realtà in questo caso non si tratta di I/O asincrono vero e proprio, quanto
-di un meccanismo asincrono di notifica delle variazione dello stato del file
-descriptor; quello che succede è che il sistema genera un segnale (normalmente
-\const{SIGIO}, ma è possibile usarne altri) tutte le volte che diventa
-possibile leggere o scrivere dal file descriptor che si è posto in questa
-modalità. Si può inoltre selezionare, con il comando \const{F\_SETOWN} di
-\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale. 
+\secref{sec:file_fcntl}). 
+
+In realtà in questo caso non si tratta di eseguire delle operazioni di lettura
+o scrittura del file in modo asincrono (tratteremo questo, che più
+propriamente è detto \textsl{I/O asincrono} in
+\secref{sec:file_asyncronous_io}), quanto di un meccanismo asincrono di
+notifica delle variazione dello stato del file descriptor aperto in questo
+modo.
+
+Quello che succede è che il sistema genera un segnale (normalmente
+\const{SIGIO}, ma è possibile usarne altri con il comando \const{F\_SETSIG} di
+\func{fcntl}) tutte le volte che diventa possibile leggere o scrivere dal file
+descriptor che si è posto in questa modalità. Si può inoltre selezionare, con
+il comando \const{F\_SETOWN} di \func{fcntl}, quale processo (o gruppo di
+processi) riceverà il segnale. Se pertanto si effettuano le operazioni in
+risposta alla ricezione del segnale non ci sarà più la necessità di restare
+bloccati in attesa della disponibilità di accesso ai file.
 
 In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select}
 che, quando vengono usate con un numero molto grande di file descriptor, non
-hanno buone prestazioni. In tal caso infatti la maggior parte del loro tempo
+hanno buone prestazioni. % aggiungere cenno a epoll quando l'avrò scritta
+ In tal caso infatti la maggior parte del loro tempo
 di esecuzione è impegnato ad eseguire una scansione su tutti i file descriptor
 tenuti sotto controllo per determinare quali di essi (in genere una piccola
 percentuale) sono diventati attivi.
 
 Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
-presenta notevoli problemi, dato che non è possibile determinare, quando sono
-più di uno, qual'è il file descriptor responsabile dell'emissione del segnale.
-Linux però supporta le estensioni POSIX.1b dei segnali che permettono di
-superare il problema facendo ricorso alle informazioni aggiuntive restituite
-attraverso la struttura \type{siginfo\_t}, utilizzando la forma estesa
-\var{sa\_sigaction} del manipolatore (si riveda quanto illustrato in
+presenta notevoli problemi, dato che non è possibile determinare, quando i
+file descriptor sono più di uno, qual'è quello responsabile dell'emissione del
+segnale; inoltre dato che i segnali normali non si accumulano, in presenza di
+più file descriptor attivi contemporaneamente, più segnali emessi nello stesso
+tempo verrebbero notificati una volta sola. Linux però supporta le estensioni
+POSIX.1b dei segnali real-time, che possono accumularsi e che permettono di
+riconoscere il file descriptor facendo ricorso alle informazioni aggiuntive
+restituite attraverso la struttura \struct{siginfo\_t}, utilizzando la forma
+estesa \var{sa\_sigaction} del gestore (si riveda quanto illustrato in
 \secref{sec:sig_sigaction}).
 
 Per far questo però occorre utilizzare le funzionalità dei segnali real-time
 (vedi \secref{sec:sig_real_time}) impostando esplicitamente con il comando
 \const{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
 I/O asincrono (il segnale predefinito è \const{SIGIO}). In questo caso il
-manipolatore tutte le volte che riceverà \const{SI\_SIGIO} come valore del
+gestore, tutte le volte che riceverà \const{SI\_SIGIO} come valore del
 campo \var{si\_code}\footnote{il valore resta \const{SI\_SIGIO} qualunque sia
   il segnale che si è associato all'I/O asincrono, ed indica appunto che il
   segnale è stato generato a causa di attività nell'I/O asincrono.} di
-\type{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file
+\struct{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file
 descriptor che ha generato il segnale.
 
 Un secondo vantaggio dell'uso dei segnali real-time è che essendo dotati di
@@ -383,32 +512,42 @@ cui l'accesso 
 come \func{poll} e \func{select}, almeno fintanto che non si satura la coda;
 si eccedono le dimensioni di quest'ultima; in tal caso infatti il kernel, non
 potendo più assicurare il comportamento corretto per un segnale real-time,
-invierà al suo posto un \var{SIGIO}, su cui si accumuleranno tutti i segnali
-in eccesso, e si dovrà determinare al solito modo quali sono i file diventati
+invierà al suo posto un \const{SIGIO}, su cui si accumuleranno tutti i segnali
+in eccesso, e si dovrà determinare con un ciclo quali sono i file diventati
 attivi.
 
+
+\subsection{L'interfaccia POSIX per l'I/O asincrono}
+\label{sec:file_asyncronous_io}
+
+Una modalità alternativa all'uso dell'\textit{I/O multiplexing} per gestione
+dell'I/O simultaneo su molti file è costituita dal cosiddetto \textsl{I/O
+  asincrono}. Il concetto base dell'\textsl{I/O asincrono} è che le funzioni
+di I/O non attendono il completamento delle operazioni prima di ritornare,
+così che il processo non viene bloccato.  In questo modo diventa ad esempio
+possibile effettuare una richiesta preventiva di dati, in modo da poter
+effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
+
 Benché la modalità di apertura asincrona di un file possa risultare utile in
-varie occasioni (in particolar modo con i socket e gli altri file per i quali
-le funzioni di I/O sono system call lente), essa è comunque limitata alla
-notifica della disponibilità del file descriptor per le operazioni di I/O, e
-non ad uno svolgimento asincrono delle medesime.  Lo standard POSIX.1b
-definisce anche una interfaccia apposita per l'I/O asincrono, che prevede un
-insieme di funzioni dedicate, completamente separate rispetto a quelle usate
-normalmente.
+varie occasioni (in particolar modo con i socket\index{socket} e gli altri
+file per i quali le funzioni di I/O sono \index{system call lente}system call
+lente), essa è comunque limitata alla notifica della disponibilità del file
+descriptor per le operazioni di I/O, e non ad uno svolgimento asincrono delle
+medesime.  Lo standard POSIX.1b definisce una interfaccia apposita per l'I/O
+asincrono vero e proprio, che prevede un insieme di funzioni dedicate per la
+lettura e la scrittura dei file, completamente separate rispetto a quelle
+usate normalmente.
 
 In generale questa interfaccia è completamente astratta e può essere
 implementata sia direttamente nel kernel, che in user space attraverso l'uso
-di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, nella serie
-  2.5.x è però iniziato un lavoro completo di riscrittura di tutto il sistema
-  di I/O, che prevede anche l'introduzione di un nuovo layer per l'I/O
-  asincrono (effettuato a partire dal 2.5.32).} esiste una sola versione
-stabile di questa interfaccia, quella delle \acr{glibc}, che è realizzata
-completamente in user space.  Esistono comunque vari progetti sperimentali
-(come il KAIO della SGI, o i patch di Benjamin La Haise) che prevedono un
-supporto diretto da parte del kernel.
+di thread. Al momento esiste una sola versione stabile di questa interfaccia,
+quella delle \acr{glibc}, che è realizzata completamente in user space, ed
+accessibile linkando i programmi con la libreria \file{librt}. Nei kernel
+della nuova serie è stato anche introdotta (a partire dal 2.5.32) un nuovo
+layer per l'I/O asincrono.
 
 Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
-attraverso l'uso di una apposita struttura \type{aiocb} (il cui nome sta per
+attraverso l'uso di una apposita struttura \struct{aiocb} (il cui nome sta per
 \textit{asyncronous I/O control block}), che viene passata come argomento a
 tutte le funzioni dell'interfaccia. La sua definizione, come effettuata in
 \file{aio.h}, è riportata in \figref{fig:file_aiocb}. Nello steso file è
@@ -418,38 +557,26 @@ disponibilit
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct aiocb
-{
-    int aio_fildes;               /* File descriptor.  */
-    off_t aio_offset;             /* File offset */
-    int aio_lio_opcode;           /* Operation to be performed.  */
-    int aio_reqprio;              /* Request priority offset.  */
-    volatile void *aio_buf;       /* Location of buffer.  */
-    size_t aio_nbytes;            /* Length of transfer.  */
-    struct sigevent aio_sigevent; /* Signal number and value.  */
-};
-    \end{lstlisting}
+    \includestruct{listati/aiocb.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \type{aiocb}, usata per il controllo dell'I/O
+  \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O
     asincrono.}
   \label{fig:file_aiocb}
 \end{figure}
 
 Le operazioni di I/O asincrono possono essere effettuate solo su un file già
-aperto; il file deve inoltre supportare la funzione \func{lseek},
-pertanto terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
-contemporanee effettuabili su un singolo file.
-
-Ogni operazione deve inizializzare opportunamente un \textit{control block}.
-Il file descriptor su cui operare deve essere specificato tramite il campo
-\var{aio\_fildes}; dato che più operazioni possono essere eseguita in maniera
-asincrona, il concetto di posizione corrente sul file viene a mancare;
-pertanto si deve sempre specificare nel campo \var{aio\_offset} la posizione
-sul file da cui i dati saranno letti o scritti.  Nel campo \var{aio\_buf} deve
-essere specificato l'indirizzo del buffer usato per l'I/O, ed in
-\var{aio\_nbytes} la lunghezza del blocco di dati da trasferire.
+aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto
+terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
+contemporanee effettuabili su un singolo file.  Ogni operazione deve
+inizializzare opportunamente un \textit{control block}.  Il file descriptor su
+cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato
+che più operazioni possono essere eseguita in maniera asincrona, il concetto
+di posizione corrente sul file viene a mancare; pertanto si deve sempre
+specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati
+saranno letti o scritti.  Nel campo \var{aio\_buf} deve essere specificato
+l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza
+del blocco di dati da trasferire.
 
 Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni
 di I/O.\footnote{in generale perché ciò sia possibile occorre che la
@@ -457,54 +584,45 @@ di I/O.\footnote{in generale perch
   le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
   \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene impostata a
 partire da quella del processo chiamante (vedi \secref{sec:proc_priority}),
-cui viene sottratto il valore di questo campo.
-
-Il campo \var{aio\_lio\_opcode} è usato soltanto dalla funzione
-\func{lio\_listio}, che, come vedremo più avanti, permette di eseguire con una
-sola chiamata una serie di operazioni, usando un vettore di \textit{control
-  block}. Tramite questo campo si specifica quale è la natura di ciascuna di
-esse.
+cui viene sottratto il valore di questo campo.  Il campo
+\var{aio\_lio\_opcode} è usato solo dalla funzione \func{lio\_listio}, che,
+come vedremo, permette di eseguire con una sola chiamata una serie di
+operazioni, usando un vettore di \textit{control block}. Tramite questo campo
+si specifica quale è la natura di ciascuna di esse.
 
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct sigevent
-{
-    sigval_t sigev_value;
-    int sigev_signo;
-    int sigev_notify;
-    sigev_notify_function;
-    sigev_notify_attributes;
-};
-    \end{lstlisting}
+    \includestruct{listati/sigevent.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \type{sigevent}, usata per specificare le modalità di
-    notifica degli eventi relativi alle operazioni di I/O asincrono.}
+  \caption{La struttura \structd{sigevent}, usata per specificare le modalità
+    di notifica degli eventi relativi alle operazioni di I/O asincrono.}
   \label{fig:file_sigevent}
 \end{figure}
 
-Infine il campo \var{aio\_sigevent} è una struttura di tipo \type{sigevent}
+Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
 che serve a specificare il modo in cui si vuole che venga effettuata la
 notifica del completamento delle operazioni richieste. La struttura è
 riportata in \secref{fig:file_sigevent}; il campo \var{sigev\_notify} è quello
 che indica le modalità della notifica, esso può assumere i tre valori:
-\begin{basedescript}{\desclabelwidth{3.0cm}}
-\item[\const{SIGEV\_NONE}]   Non viene inviata nessuna notifica.
+\begin{basedescript}{\desclabelwidth{2.6cm}}
+\item[\const{SIGEV\_NONE}]  Non viene inviata nessuna notifica.
 \item[\const{SIGEV\_SIGNAL}] La notifica viene effettuata inviando al processo
-  chiamante il segnale specificato nel campo \var{sigev\_signo}, se il
-  manipolatore è installato con \const{SA\_SIGINFO}, il gli verrà restituito
-  il valore di \var{sigev\_value} in come valore del campo \var{si\_value} per
-  \type{siginfo\_t}.
+  chiamante il segnale specificato da \var{sigev\_signo}; se il gestore di
+  questo è stato installato con \const{SA\_SIGINFO} gli verrà restituito il
+  valore di \var{sigev\_value} (la cui definizione è in
+  \figref{fig:sig_sigval}) come valore del campo \var{si\_value} di
+  \struct{siginfo\_t}.
 \item[\const{SIGEV\_THREAD}] La notifica viene effettuata creando un nuovo
-  thread che esegue la funzione specificata da \var{sigev\_notify\_function},
-  con gli attributi specificati da \var{sigev\_notify\_attribute}.
+  thread che esegue la funzione specificata da \var{sigev\_notify\_function}
+  con argomento \var{sigev\_value}, e con gli attributi specificati da
+  \var{sigev\_notify\_attribute}.
 \end{basedescript}
 
 Le due funzioni base dell'interfaccia per l'I/O asincrono sono
-\func{aio\_read} ed \func{aio\_write}.  Esse permettono di richiedere una
-lettura od una scrittura asincrona di dati, usando la struttura \type{aiocb}
+\funcd{aio\_read} ed \funcd{aio\_write}.  Esse permettono di richiedere una
+lettura od una scrittura asincrona di dati, usando la struttura \struct{aiocb}
 appena descritta; i rispettivi prototipi sono:
 \begin{functions}
   \headdecl{aio.h}
@@ -541,17 +659,17 @@ Si tenga inoltre presente che deallocare la memoria indirizzata da
 \param{aiocbp} o modificarne i valori prima della conclusione di una
 operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari
 campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la
-richiesta.  Questo comporta che occorre evitare di usare per \param{aiocbp}
+richiesta.  Questo comporta che non si devono usare per \param{aiocbp}
 variabili automatiche e che non si deve riutilizzare la stessa struttura per
-un ulteriore operazione fintanto che la precedente non sia stata ultimata. In
-generale per ogni operazione di I/O asincrono si deve utilizzare una diversa
-struttura \type{aiocb}.
+un'altra operazione fintanto che la precedente non sia stata ultimata. In
+generale per ogni operazione si deve utilizzare una diversa struttura
+\struct{aiocb}.
 
 Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o
 \func{aio\_write} non implica che le operazioni siano state effettivamente
 eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
 altre due funzioni, che permettono di controllare lo stato di esecuzione. La
-prima è \func{aio\_error}, che serve a determinare un eventuale stato di
+prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
 errore; il suo prototipo è:
 \begin{prototype}{aio.h}
   {int aio\_error(const struct aiocb *aiocbp)}  
@@ -575,8 +693,8 @@ del caso, i codici di errore delle system call \func{read}, \func{write} e
 \func{fsync}.
 
 Una volta che si sia certi che le operazioni siano state concluse (cioè dopo
-che una chiamata ad \func{aio\_error} non ha restituito \errcode{EINPROGRESS},
-si potrà usare la seconda funzione dell'interfaccia, \func{aio\_return}, che
+che una chiamata ad \func{aio\_error} non ha restituito
+\errcode{EINPROGRESS}), si potrà usare la funzione \funcd{aio\_return}, che
 permette di verificare il completamento delle operazioni di I/O asincrono; il
 suo prototipo è:
 \begin{prototype}{aio.h}
@@ -603,7 +721,7 @@ asincrono non verrebbero liberate, rischiando di arrivare ad un loro
 esaurimento.
 
 Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
-disposizione un'altra operazione, quella di sincronizzazione dell'I/O, essa è
+disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
 compiuta dalla funzione \func{aio\_fsync}, che ha lo stesso effetto della
 analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
 è:
@@ -634,7 +752,7 @@ operazioni di sincronizzazione dei dati saranno completate.
 
 In alcuni casi può essere necessario interrompere le operazioni (in genere
 quando viene richiesta un'uscita immediata dal programma), per questo lo
-standard POSIX.1b prevede una funzioni apposita, \func{aio\_cancel}, che
+standard POSIX.1b prevede una funzioni apposita, \funcd{aio\_cancel}, che
 permette di cancellare una operazione richiesta in precedenza; il suo
 prototipo è:
 \begin{prototype}{aio.h}
@@ -677,7 +795,7 @@ corso normale, compreso quanto richiesto riguardo al meccanismo di notifica
 del loro avvenuto completamento.
 
 Benché l'I/O asincrono preveda un meccanismo di notifica, l'interfaccia
-fornisce anche una apposita funzione, \func{aio\_suspend}, che permette di
+fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
 sospendere l'esecuzione del processo chiamante fino al completamento di una
 specifica operazione; il suo prototipo è:
 \begin{prototype}{aio.h}
@@ -704,12 +822,12 @@ La funzione permette di bloccare il processo fintanto che almeno una delle
 un tempo massimo specificato da \param{timout}, o fintanto che non arrivi un
 segnale.\footnote{si tenga conto che questo segnale può anche essere quello
   utilizzato come meccanismo di notifica.} La lista deve essere inizializzata
-con delle strutture \var{aiocb} relative ad operazioni effettivamente
+con delle strutture \struct{aiocb} relative ad operazioni effettivamente
 richieste, ma può contenere puntatori nulli, che saranno ignorati. In caso si
 siano specificati valori non validi l'effetto è indefinito.  Un valore
 \val{NULL} per \param{timout} comporta l'assenza di timeout.
 
-Lo standard POSIX.1b infine ha previsto pure una funzione, \func{lio\_listio},
+Lo standard POSIX.1b infine ha previsto pure una funzione, \funcd{lio\_listio},
 che permette di effettuare la richiesta di una intera lista di operazioni di
 lettura o scrittura; il suo prototipo è:
 \begin{prototype}{aio.h}
@@ -724,6 +842,9 @@ lettura o scrittura; il suo prototipo 
     \begin{errlist}
     \item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro
       \param{timeout}.
+    \item[\errcode{EINVAL}] Si è passato un valore di \param{mode} non valido
+      o un numero di operazioni \param{nent} maggiore di
+      \const{AIO\_LISTIO\_MAX}.
     \item[\errcode{ENOSYS}] La funzione non è implementata.
     \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
     \end{errlist}
@@ -752,9 +873,19 @@ specifica \const{LIO\_NOWAIT} la funzione ritorna immediatamente dopo aver
 messo in coda tutte le richieste. In questo caso il chiamante può richiedere
 la notifica del completamento di tutte le richieste, impostando l'argomento
 \param{sig} in maniera analoga a come si fa per il campo \var{aio\_sigevent}
-di \type{aiocb}.
+di \struct{aiocb}.
 
 
+\section{Altre modalità di I/O avanzato}
+\label{sec:file_advanced_io}
+
+Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
+  asincrono}, esistono altre funzioni che implementano delle modalità di
+accesso ai file più evolute rispetto alle normali funzioni di lettura e
+scrittura che abbiamo esaminato in \secref{sec:file_base_func}. In questa
+sezione allora prenderemo in esame le interfacce per l'\textsl{I/O
+  vettorizzato} e per l'\textsl{I/O mappato in memoria}.
+
 
 \subsection{I/O vettorizzato}
 \label{sec:file_multiple_io}
@@ -768,10 +899,10 @@ chiamate, ci sono casi in cui si vuole poter contare sulla atomicit
 operazioni.
 
 Per questo motivo BSD 4.2\footnote{Le due funzioni sono riprese da BSD4.4 ed
-  integrate anche dallo standard Unix 98; fino alle libc5 Linux usava
+  integrate anche dallo standard Unix 98. Fino alle libc5, Linux usava
   \type{size\_t} come tipo dell'argomento \param{count}, una scelta logica,
   che però è stata dismessa per restare aderenti allo standard.} ha introdotto
-due nuove system call, \func{readv} e \func{writev}, che permettono di
+due nuove system call, \funcd{readv} e \funcd{writev}, che permettono di
 effettuare con una sola chiamata una lettura o una scrittura su una serie di
 buffer (quello che viene chiamato \textsl{I/O vettorizzato}. I relativi
 prototipi sono:
@@ -805,7 +936,7 @@ prototipi sono:
   usuali funzioni di lettura e scrittura eseguite su \param{fd}.}
 \end{functions}
 
-Entrambe le funzioni usano una struttura \type{iovec}, definita in
+Entrambe le funzioni usano una struttura \struct{iovec}, definita in
 \figref{fig:file_iovec}, che definisce dove i dati devono essere letti o
 scritti. Il primo campo, \var{iov\_base}, contiene l'indirizzo del buffer ed
 il secondo, \var{iov\_len}, la dimensione dello stesso. 
@@ -813,25 +944,20 @@ il secondo, \var{iov\_len}, la dimensione dello stesso.
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct iovec {
-    __ptr_t iov_base;    /* Starting address */
-    size_t iov_len;      /* Length in bytes  */
-};
-    \end{lstlisting}
+    \includestruct{listati/iovec.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \type{iovec}, usata dalle operazioni di I/O
+  \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
     vettorizzato.} 
   \label{fig:file_iovec}
 \end{figure}
 
 I buffer da utilizzare sono indicati attraverso l'argomento \param{vector} che
-è un vettore di strutture \var{iovec}, la cui lunghezza è specificata da
+è un vettore di strutture \struct{iovec}, la cui lunghezza è specificata da
 \param{count}.  Ciascuna struttura dovrà essere inizializzata per
 opportunamente per indicare i vari buffer da/verso i quali verrà eseguito il
 trasferimento dei dati. Essi verranno letti (o scritti) nell'ordine in cui li
-si sono specificati nel vettore \var{vector}.
+si sono specificati nel vettore \param{vector}.
 
 
 \subsection{File mappati in memoria}
@@ -846,13 +972,13 @@ file in una sezione dello spazio di indirizzi del processo. Il meccanismo 
 illustrato in \figref{fig:file_mmap_layout}, una sezione del file viene
 riportata direttamente nello spazio degli indirizzi del programma. Tutte le
 operazioni su questa zona verranno riportate indietro sul file dal meccanismo
-della memoria virtuale che trasferirà il contenuto di quel segmento sul file
-invece che nella swap, per cui si può parlare tanto di file mappato in
-memoria, quanto di memoria mappata su file.
+della memoria virtuale\index{memoria virtuale} che trasferirà il contenuto di
+quel segmento sul file invece che nella swap, per cui si può parlare tanto di
+file mappato in memoria, quanto di memoria mappata su file.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=9.5cm]{img/mmap_layout}
+  \includegraphics[width=7.cm]{img/mmap_layout}
   \caption{Disposizione della memoria di un processo quando si esegue la
   mappatura in memoria di un file.}
   \label{fig:file_mmap_layout}
@@ -867,20 +993,19 @@ memoria solo le parti del file che sono effettivamente usate ad un dato
 istante.
 
 Infatti, dato che l'accesso è fatto direttamente attraverso la memoria
-virtuale, la sezione di memoria mappata su cui si opera sarà a sua volta letta
-o scritta sul file una pagina alla volta e solo per le parti effettivamente
-usate, il tutto in maniera completamente trasparente al processo; l'accesso
-alle pagine non ancora caricate avverrà allo stesso modo con cui vengono
-caricate in memoria le pagine che sono state salvate sullo swap.
-
-Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un
-file vengono salvate automaticamente, così come le pagine dei programmi
-vengono scritte sulla swap; questo consente di accedere ai file su dimensioni
-il cui solo limite è quello dello spazio di indirizzi disponibile, e non della
-memoria su cui possono esserne lette delle porzioni.
+virtuale,\index{memoria virtuale} la sezione di memoria mappata su cui si
+opera sarà a sua volta letta o scritta sul file una pagina alla volta e solo
+per le parti effettivamente usate, il tutto in maniera completamente
+trasparente al processo; l'accesso alle pagine non ancora caricate avverrà
+allo stesso modo con cui vengono caricate in memoria le pagine che sono state
+salvate sullo swap.  Infine in situazioni in cui la memoria è scarsa, le
+pagine che mappano un file vengono salvate automaticamente, così come le
+pagine dei programmi vengono scritte sulla swap; questo consente di accedere
+ai file su dimensioni il cui solo limite è quello dello spazio di indirizzi
+disponibile, e non della memoria su cui possono esserne lette delle porzioni.
 
 L'interfaccia prevede varie funzioni per la gestione del \textit{memory mapped
-  I/O}, la prima di queste è \func{mmap}, che serve ad eseguire la mappatura
+  I/O}, la prima di queste è \funcd{mmap}, che serve ad eseguire la mappatura
 in memoria di un file; il suo prototipo è:
 \begin{functions}
   
@@ -898,12 +1023,11 @@ in memoria di un file; il suo prototipo 
     \begin{errlist}
     \item[\errcode{EBADF}] Il file descriptor non è valido, e non si è usato
       \const{MAP\_ANONYMOUS}.
-    \item[\errcode{EACCES}] Il file descriptor non si riferisce ad un file
-      regolare, o si è richiesto \const{MAP\_PRIVATE} ma \param{fd} non è
-      aperto in lettura, o si è richiesto \const{MAP\_SHARED} e impostato
-      \const{PROT\_WRITE} ed \param{fd} non è aperto in lettura/scrittura, o
-      si è impostato \const{PROT\_WRITE} ed \param{fd} è in
-      \textit{append-only}.
+    \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare,
+      o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
+      o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
+      \param{fd} non è aperto in lettura/scrittura, o si è impostato
+      \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
     \item[\errcode{EINVAL}] I valori di \param{start}, \param{length} o
       \param{offset} non sono validi (o troppo grandi o non allineati sulla
       dimensione delle pagine).
@@ -1031,25 +1155,13 @@ come maschera binaria ottenuta dall'OR di uno o pi
 Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
 piuttosto complessi, essi si possono comprendere solo tenendo presente che
 tutto quanto è comunque basato sul basato sul meccanismo della memoria
-virtuale. Questo comporta allora una serie di conseguenze. La più ovvia è che
-se si cerca di scrivere su una zona mappata in sola lettura si avrà
-l'emissione di un segnale di violazione di accesso (\const{SIGSEGV}), dato che
-i permessi sul segmento di memoria relativo non consentono questo tipo di
-accesso.
+virtuale.\index{memoria virtuale} Questo comporta allora una serie di
+conseguenze. La più ovvia è che se si cerca di scrivere su una zona mappata in
+sola lettura si avrà l'emissione di un segnale di violazione di accesso
+(\const{SIGSEGV}), dato che i permessi sul segmento di memoria relativo non
+consentono questo tipo di accesso.
 
-È invece assai diversa la questione relativa agli accessi al di fuori della
-regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
-ritenere che anch'essi debbano generare un segnale di violazione di accesso;
-questo però non tiene conto del fatto che, essendo basata sul meccanismo della
-paginazione, la mappatura in memoria non può che essere eseguita su un
-segmento di dimensioni rigorosamente multiple di quelle di una pagina, ed in
-generale queste potranno non corrispondere alle dimensioni effettive del file
-o della sezione che si vuole mappare. Il caso più comune è quello illustrato
-in \figref{fig:file_mmap_boundary}, in cui la sezione di file non rientra nei
-confini di una pagina: in tal caso verrà il file sarà mappato su un segmento
-di memoria che si estende fino al bordo della pagina successiva.
-
-\begin{figure}[htb]
+\begin{figure}[!htb]
   \centering
   \includegraphics[width=10cm]{img/mmap_boundary}
   \caption{Schema della mappatura in memoria di una sezione di file di
@@ -1057,6 +1169,18 @@ di memoria che si estende fino al bordo della pagina successiva.
   \label{fig:file_mmap_boundary}
 \end{figure}
 
+È invece assai diversa la questione relativa agli accessi al di fuori della
+regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
+ritenere che anch'essi debbano generare un segnale di violazione di accesso;
+questo però non tiene conto del fatto che, essendo basata sul meccanismo della
+paginazione\index{paginazione}, la mappatura in memoria non può che essere
+eseguita su un segmento di dimensioni rigorosamente multiple di quelle di una
+pagina, ed in generale queste potranno non corrispondere alle dimensioni
+effettive del file o della sezione che si vuole mappare. Il caso più comune è
+quello illustrato in \figref{fig:file_mmap_boundary}, in cui la sezione di
+file non rientra nei confini di una pagina: in tal caso verrà il file sarà
+mappato su un segmento di memoria che si estende fino al bordo della pagina
+successiva.
 
 In questo caso è possibile accedere a quella zona di memoria che eccede le
 dimensioni specificate da \param{lenght}, senza ottenere un \const{SIGSEGV}
@@ -1072,7 +1196,7 @@ quella della mappatura in memoria.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=13cm]{img/mmap_exceed}
+  \includegraphics[width=10cm]{img/mmap_exceed}
   \caption{Schema della mappatura in memoria di file di dimensioni inferiori
     alla lunghezza richiesta.}
   \label{fig:file_mmap_exceed}
@@ -1090,7 +1214,7 @@ biunivoca fra una sezione di un file ed una sezione di memoria. Questo
 comporta che ad esempio non è possibile mappare in memoria file descriptor
 relativi a pipe, socket e fifo, per i quali non ha senso parlare di
 \textsl{sezione}. Lo stesso vale anche per alcuni file di dispositivo, che non
-dispongono della relativa operazione \var{mmap} (si ricordi quanto esposto in
+dispongono della relativa operazione \func{mmap} (si ricordi quanto esposto in
 \secref{sec:file_vfs_work}). Si tenga presente però che esistono anche casi di
 dispositivi (un esempio è l'interfaccia al ponte PCI-VME del chip Universe)
 che sono utilizzabili solo con questa interfaccia.
@@ -1127,14 +1251,14 @@ Pertanto se si modifica un file con l'interfaccia standard queste modifiche
 potranno essere visibili o meno a seconda del momento in cui la memoria
 virtuale trasporterà dal disco in memoria quella sezione del file, perciò è
 del tutto imprevedibile il risultato della modifica di un file nei confronti
-del contenuto della memoria mappata su cui è mappato.
-
-Per quanto appena visto, è sempre sconsigliabile eseguire scritture su file
-attraverso l'interfaccia standard, quando lo si è mappato in memoria, è invece
-possibile usare l'interfaccia standard per leggere un file mappato in memoria,
-purché si abbia una certa cura; infatti l'interfaccia dell'I/O mappato in
-memoria mette a disposizione la funzione \func{msync} per sincronizzare il
-contenuto della memoria mappata con il file su disco; il suo prototipo è:
+del contenuto della memoria su cui è mappato.
+
+Per questo, è sempre sconsigliabile eseguire scritture su file attraverso
+l'interfaccia standard, quando lo si è mappato in memoria, è invece possibile
+usare l'interfaccia standard per leggere un file mappato in memoria, purché si
+abbia una certa cura; infatti l'interfaccia dell'I/O mappato in memoria mette
+a disposizione la funzione \funcd{msync} per sincronizzare il contenuto della
+memoria mappata con il file su disco; il suo prototipo è:
 \begin{functions}  
   \headdecl{unistd.h}
   \headdecl{sys/mman.h} 
@@ -1190,7 +1314,7 @@ le mappature dello stesso file, cos
 aggiornate ai nuovi valori.
 
 Una volta che si sono completate le operazioni di I/O si può eliminare la
-mappatura della memoria usando la funzione \func{munmap}, il suo prototipo è:
+mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo è:
 \begin{functions}  
   \headdecl{unistd.h}
   \headdecl{sys/mman.h} 
@@ -1223,6 +1347,7 @@ mappatura in memoria non ha alcun effetto sulla stessa.
 \section{Il file locking}
 \label{sec:file_locking}
 
+\index{file!locking|(}
 In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
 sistema unix-like gestisce la condivisione dei file da parte di processi
 diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
@@ -1237,9 +1362,10 @@ 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, 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 race condition\index{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.
 
 
 
@@ -1259,29 +1385,30 @@ sistemi unix-like 
   mantenere il nome \textit{advisory locking}.} in quanto sono i singoli
 processi, e non il sistema, che si incaricano di asserire e verificare se
 esistono delle condizioni di blocco per l'accesso ai file.  Questo significa
-che le funzioni \func{read} o \func{write} non risentono affatto della
-presenza di un eventuale \textit{lock}, e che sta ai vari processi controllare
-esplicitamente lo stato dei file condivisi prima di accedervi, implementando
-un opportuno protocollo.
+che le funzioni \func{read} o \func{write} vengono eseguite comunque e non
+risentono affatto della presenza di un eventuale \textit{lock}; pertanto è
+sempre compito dei vari processi che intendono usare il file locking,
+controllare esplicitamente lo stato dei file condivisi prima di accedervi,
+utilizzando le relative funzioni.
 
 In generale si distinguono due tipologie di \textit{file lock}:\footnote{di
   seguito ci riferiremo sempre ai blocchi di accesso ai file con la
   nomenclatura inglese di \textit{file lock}, o più brevemente con
-  \textit{lock}, per evitare confuzioni linguistiche con il blocco di un
+  \textit{lock}, per evitare confusioni linguistiche con il blocco di un
   processo (cioè la condizione in cui il processo viene posto in stato di
   \textit{sleep}).} la prima è il cosiddetto \textit{shared lock}, detto anche
 \textit{read lock} in quanto serve a bloccare l'accesso in scrittura su un
-file affinché non venga modificato mentre lo si legge. Si parla appunto di
-\textsl{blocco condiviso} in quanto più processi possono richiedere
-contemporaneamente uno \textit{shared lock} su un file per proteggere il loro
-accesso in lettura.
+file affinché il suo contenuto non venga modificato mentre lo si legge. Si
+parla appunto di \textsl{blocco condiviso} in quanto più processi possono
+richiedere contemporaneamente uno \textit{shared lock} su un file per
+proteggere il loro accesso in lettura.
 
 La seconda tipologia è il cosiddetto \textit{exclusive lock}, detto anche
 \textit{write lock} in quanto serve a bloccare l'accesso su un file (sia in
 lettura che in scrittura) da parte di altri processi mentre lo si sta
 scrivendo. Si parla di \textsl{blocco esclusivo} appunto perché un solo
 processo alla volta può richiedere un \textit{exclusive lock} su un file per
-proteggere il suo accesso in scrittura. 
+proteggere il suo accesso in scrittura.
 
 \begin{table}[htb]
   \centering
@@ -1315,12 +1442,17 @@ lettura) prima di eseguire l'accesso ad un file.  Se il lock viene acquisito
 il processo prosegue l'esecuzione, altrimenti (a meno di non aver richiesto un
 comportamento non bloccante) viene posto in stato di sleep. Una volta finite
 le operazioni sul file si deve provvedere a rimuovere il lock. La situazione
-delle varie possibilità è riassunta in \tabref{tab:file_file_lock}.
-
-Si tenga presente infine che il controllo di accesso è effettuato quando si
-apre un file, l'unico controllo residuo è che il tipo di lock che si vuole
-otternere deve essere compatibile con le modalità di apertura dello stesso (di
-lettura per un read lock e di scrittura per un write lock).
+delle varie possibilità è riassunta in \tabref{tab:file_file_lock}, dove si
+sono riportati, per le varie tipologie di lock presenti su un file, il
+risultato che si ha in corrispondenza alle due tipologie di \textit{file lock}
+menzionate, nel successo della richiesta.
+
+Si tenga presente infine che il controllo di accesso e la gestione dei
+permessi viene effettuata quando si apre un file, l'unico controllo residuo
+che si può avere riguardo il \textit{file locking} è che il tipo di lock che
+si vuole ottenere su un file deve essere compatibile con le modalità di
+apertura dello stesso (in lettura per un read lock e in scrittura per un write
+lock).
 
 %%  Si ricordi che
 %% la condizione per acquisire uno \textit{shared lock} è che il file non abbia
@@ -1328,12 +1460,12 @@ lettura per un read lock e di scrittura per un write lock).
 %% \textit{exclusive lock} non deve essere presente nessun tipo di blocco.
 
 
-\subsection{La funzione \func{flock}}
+\subsection{La funzione \func{flock}} 
 \label{sec:file_flock}
 
 La prima interfaccia per il file locking, quella derivata da BSD, permette di
 eseguire un blocco solo su un intero file; la funzione usata per richiedere e
-rimuovere un \textit{file lock} è \func{flock}, ed il suo prototipo è:
+rimuovere un \textit{file lock} è \funcd{flock}, ed il suo prototipo è:
 \begin{prototype}{sys/file.h}{int flock(int fd, int operation)}
   
   Applica o rimuove un \textit{file lock} sul file \param{fd}.
@@ -1390,20 +1522,20 @@ dell'implementazione del file locking in stile BSD in Linux; il punto
 fondamentale da capire è che un lock, qualunque sia l'interfaccia che si usa,
 anche se richiesto attraverso un file descriptor, agisce sempre su un file;
 perciò le informazioni relative agli eventuali \textit{file lock} sono
-mantenute a livello di inode,\footnote{in particolare, come accennato in
-  \figref{fig:file_flock_struct}, i \textit{file lock} sono mantenuti un una
-  \textit{linked list}\index{linked list} di strutture \var{file\_lock}. La
-  lista è referenziata dall'indirizzo di partenza mantenuto dal campo
-  \var{i\_flock} della struttura \var{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.
+mantenute a livello di inode\index{inode},\footnote{in particolare, come
+  accennato in \figref{fig:file_flock_struct}, i \textit{file lock} sono
+  mantenuti un una \textit{linked list}\index{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.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=12.5cm]{img/file_flock}
+  \includegraphics[width=14cm]{img/file_flock}
   \caption{Schema dell'architettura del file locking, nel caso particolare  
     del suo utilizzo da parte dalla funzione \func{flock}.}
   \label{fig:file_flock_struct}
@@ -1411,15 +1543,15 @@ stesso file.
 
 La richiesta di un file lock prevede una scansione della lista per determinare
 se l'acquisizione è possibile, ed in caso positivo l'aggiunta di un nuovo
-elemento.\footnote{cioè una nuova struttura \var{file\_lock}.}  Nel caso dei
-lock creati con \func{flock} la semantica della funzione prevede che sia
+elemento.\footnote{cioè una nuova struttura \struct{file\_lock}.}  Nel caso
+dei lock creati con \func{flock} la semantica della funzione prevede che sia
 \func{dup} che \func{fork} non creino ulteriori istanze di un file lock quanto
 piuttosto degli ulteriori riferimenti allo stesso. Questo viene realizzato dal
 kernel secondo lo schema di \figref{fig:file_flock_struct}, associando ad ogni
 nuovo \textit{file lock} un puntatore\footnote{il puntatore è mantenuto nel
-  campo \var{fl\_file} di \var{file\_lock}, e viene utilizzato solo per i lock
-  creati con la semantica BSD.} alla voce nella \textit{file table} da cui si
-è richiesto il lock, che così ne identifica il titolare.
+  campo \var{fl\_file} di \struct{file\_lock}, e viene utilizzato solo per i
+  lock creati con la semantica BSD.} alla voce nella \textit{file table} da
+cui si è richiesto il lock, che così ne identifica il titolare.
 
 Questa struttura prevede che, quando si richiede la rimozione di un file lock,
 il kernel acconsenta solo se la richiesta proviene da un file descriptor che
@@ -1481,8 +1613,8 @@ essa viene usata solo secondo il prototipo:
     \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}. Non è garantito che il sistema riconosca sempre
-      questa situazione.
+      \textit{deadlock}\index{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}
@@ -1494,28 +1626,20 @@ Al contrario di quanto avviene con l'interfaccia basata su \func{flock} con
 \func{fcntl} è possibile bloccare anche delle singole sezioni di un file, fino
 al singolo byte. Inoltre la funzione permette di ottenere alcune informazioni
 relative agli eventuali lock preesistenti.  Per poter fare tutto questo la
-funzione utilizza come terzo argomento una apposita struttura \var{flock} (la
-cui definizione è riportata in \figref{fig:struct_flock}) nella quale inserire
-tutti i dati relativi ad un determinato lock. Si tenga presente poi che un
-lock fa sempre riferimento ad una regione, per cui si potrà avere un conflitto
-anche se c'è soltanto una sovrapposizione parziale con un'altra regione
-bloccata.
+funzione utilizza come terzo argomento una apposita struttura \struct{flock}
+(la cui definizione è riportata in \figref{fig:struct_flock}) nella quale
+inserire tutti i dati relativi ad un determinato lock. Si tenga presente poi
+che un lock fa sempre riferimento ad una regione, per cui si potrà avere un
+conflitto anche se c'è soltanto una sovrapposizione parziale con un'altra
+regione bloccata.
 
 \begin{figure}[!bht]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
-struct flock {
-    short int l_type;   /* Type of lock: F_RDLCK, F_WRLCK, or F_UNLCK.  */
-    short int l_whence; /* Where `l_start' is relative to (like `lseek').  */
-    off_t l_start;      /* Offset where the lock begins.  */
-    off_t l_len;        /* Size of the locked area; zero means until EOF.  */
-    pid_t l_pid;        /* Process holding the lock.  */
-};
-    \end{lstlisting}
+    \includestruct{listati/flock.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \type{flock}, usata da \func{fcntl} per il file
+  \caption{La struttura \structd{flock}, usata da \func{fcntl} per il file
     locking.} 
   \label{fig:struct_flock}
 \end{figure}
@@ -1538,14 +1662,6 @@ file; in questo modo 
 un certo punto fino alla fine del file, coprendo automaticamente quanto
 eventualmente aggiunto in coda allo stesso.
 
-Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
-può assumere i tre valori definiti dalle costanti riportate in
-\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno
-\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock
-precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in
-caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta
-il \acr{pid} del processo che detiene il lock.
-
 \begin{table}[htb]
   \centering
   \footnotesize
@@ -1559,11 +1675,19 @@ il \acr{pid} del processo che detiene il lock.
     \const{F\_UNLCK} & Richiede l'eliminazione di un file lock.\\
     \hline    
   \end{tabular}
-  \caption{Valori possibili per il campo \var{l\_type} di \func{flock}.}
+  \caption{Valori possibili per il campo \var{l\_type} di \struct{flock}.}
   \label{tab:file_flock_type}
 \end{table}
 
-Oltre a quanto richiesto tramite i campi di \var{flock}, l'operazione
+Il tipo di file lock richiesto viene specificato dal campo \var{l\_type}, esso
+può assumere i tre valori definiti dalle costanti riportate in
+\tabref{tab:file_flock_type}, che permettono di richiedere rispettivamente uno
+\textit{shared lock}, un \textit{esclusive lock}, e la rimozione di un lock
+precedentemente acquisito. Infine il campo \var{l\_pid} viene usato solo in
+caso di lettura, quando si chiama \func{fcntl} con \const{F\_GETLK}, e riporta
+il \acr{pid} del processo che detiene il lock.
+
+Oltre a quanto richiesto tramite i campi di \struct{flock}, l'operazione
 effettivamente svolta dalla funzione è stabilita dal valore dall'argomento
 \param{cmd} che, come già riportato in \secref{sec:file_fcntl}, specifica
 l'azione da compiere; i valori relativi al file locking sono tre:
@@ -1609,7 +1733,7 @@ stato effettivamente acquisito.
 
 \begin{figure}[htb]
   \centering \includegraphics[width=9cm]{img/file_lock_dead}
-  \caption{Schema di una situazione di \textit{deadlock}.}
+  \caption{Schema di una situazione di \textit{deadlock}\index{deadlock}.}
   \label{fig:file_flock_dead}
 \end{figure}
 
@@ -1624,8 +1748,8 @@ volta di ottenere un lock sulla regione A? Questa 
 porta ad un \textit{deadlock}\index{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}.
+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}
@@ -1641,23 +1765,23 @@ esaminiamo pi
 strutture utilizzate è riportato in \figref{fig:file_posix_lock}; come si vede
 esso è molto simile all'analogo di \figref{fig:file_flock_struct}:\footnote{in
   questo caso nella figura si sono evidenziati solo i campi di
-  \var{file\_lock} significativi per la semantica POSIX, in particolare adesso
-  ciascuna struttura contiene, oltre al \acr{pid} del processo in
+  \struct{file\_lock} significativi per la semantica POSIX, in particolare
+  adesso ciascuna struttura contiene, oltre al \acr{pid} del processo in
   \var{fl\_pid}, la sezione di file che viene bloccata grazie ai campi
   \var{fl\_start} e \var{fl\_end}.  La struttura è comunque la stessa, solo
   che in questo caso nel campo \var{fl\_flags} è impostato il bit
   \const{FL\_POSIX} ed il campo \var{fl\_file} non viene usato.} il lock è
-sempre associato all'inode, solo che in questo caso la titolarità non viene
-identificata con il riferimento ad una voce nella file table, ma con il valore
-del \acr{pid} del processo.
+sempre associato all'inode\index{inode}, solo che in questo caso la titolarità
+non viene identificata con il riferimento ad una voce nella file table, ma con
+il valore del \acr{pid} del processo.
 
 Quando si richiede un lock il kernel effettua una scansione di tutti i lock
 presenti sul file\footnote{scandisce cioè la linked list delle strutture
-  \var{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 una già bloccata,
-in caso affermativo decide in base al tipo di lock, in caso negativo il nuovo
-lock viene comunque acquisito ed aggiunto alla lista.
+  \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
+una già bloccata, in caso affermativo decide in base al tipo di lock, in caso
+negativo il nuovo lock viene comunque acquisito ed aggiunto alla lista.
 
 Nel caso di rimozione invece questa viene effettuata controllando che il
 \acr{pid} del processo richiedente corrisponda a quello contenuto nel lock.
@@ -1680,7 +1804,7 @@ lock relativi al file cui esso faceva riferimento, anche se questi fossero
 stati creati usando altri file descriptor che restano aperti.
 
 Dato che il controllo sull'accesso ai lock viene eseguito sulla base del
-\acr{pid} del processo, possiamo anche prendere in cosiderazione un'altro
+\acr{pid} del processo, possiamo anche prendere in considerazione un'altro
 degli aspetti meno chiari di questa interfaccia e cioè cosa succede quando si
 richiedono dei lock su regioni che si sovrappongono fra loro all'interno
 stesso processo. Siccome il controllo, come nel caso della rimozione, si basa
@@ -1689,7 +1813,7 @@ avranno sempre successo.
 
 Nel caso della semantica BSD, essendo i lock relativi a tutto un file e non
 accumulandosi,\footnote{questa ultima caratteristica è vera in generale, se
-  cioè si richiede più volte lo stesso file lock, o più lock sula stessa
+  cioè si richiede più volte lo stesso file lock, o più lock sulla stessa
   sezione di file, le richieste non si cumulano e basta una sola richiesta di
   rilascio per cancellare il lock.}  la cosa non ha alcun effetto; la funzione
 ritorna con successo, senza che il kernel debba modificare la lista dei lock.
@@ -1709,60 +1833,7 @@ necessario a soddisfare l'operazione richiesta.
 \begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{15cm}
-    \begin{lstlisting}{}
-int main(int argc, char *argv[])
-{
-    int type = F_UNLCK;            /* lock type: default to unlock (invalid) */
-    off_t start = 0;             /* start of the locked region: default to 0 */
-    off_t len = 0;              /* length of the locked region: default to 0 */
-    int fd, res, i;                                    /* internal variables */
-    int bsd = 0;                          /* semantic type: default to POSIX */
-    int cmd = F_SETLK;              /* lock command: default to non-blocking */
-    struct flock lock;                                /* file lock structure */
-    ...
-    if ((argc - optind) != 1) {          /* There must be remaing parameters */
-        printf("Wrong number of arguments %d\n", argc - optind);
-        usage();
-    }
-    if (type == F_UNLCK) {            /* There must be a -w or -r option set */
-        printf("You should set a read or a write lock\n");
-        usage();
-    }
-    fd = open(argv[optind], O_RDWR);           /* open the file to be locked */
-    if (fd < 0) {                                           /* on error exit */
-        perror("Wrong filename");
-        exit(1);
-    }
-    /* do lock */
-    if (bsd) {                                             /* if BSD locking */
-        /* rewrite cmd for suitables flock operation values */ 
-        if (cmd == F_SETLKW) {                             /* if no-blocking */
-            cmd = LOCK_NB;              /* set the value for flock operation */
-        } else {                                                     /* else */
-            cmd = 0;                                      /* default is null */
-        }
-        if (type == F_RDLCK) cmd |= LOCK_SH;          /* set for shared lock */
-        if (type == F_WRLCK) cmd |= LOCK_EX;       /* set for exclusive lock */
-        res = flock(fd, cmd);                                /* esecute lock */
-    } else {                                             /* if POSIX locking */
-        /* setting flock structure */
-        lock.l_type = type;                       /* set type: read or write */
-        lock.l_whence = SEEK_SET;    /* start from the beginning of the file */
-        lock.l_start = start;          /* set the start of the locked region */
-        lock.l_len = len;             /* set the length of the locked region */
-        res = fcntl(fd, cmd, &lock);                              /* do lock */
-    }
-    /* check lock results */
-    if (res) {                                              /* on error exit */
-        perror("Failed lock");
-        exit(1);
-    } else {                                           /* else write message */
-        printf("Lock acquired\n");
-    }
-    pause();                       /* stop the process, use a signal to exit */
-    return 0;
-}
-    \end{lstlisting}
+    \includecodesample{listati/Flock.c}
   \end{minipage} 
   \normalsize 
   \caption{Sezione principale del codice del programma \file{Flock.c}.}
@@ -1899,7 +1970,7 @@ Failed lock: Resource temporarily unavailable
 \end{verbatim}%$
 \end{minipage}\vspace{1mm}
 \par\noindent
-come ci aspettimo questo non sarà consentito.
+come ci aspettiamo questo non sarà consentito.
 
 Il programma di norma esegue il tentativo di acquisire il lock in modalità non
 bloccante, se però usiamo l'opzione \cmd{-b} possiamo impostare la modalità
@@ -1914,7 +1985,7 @@ opzione:
 \end{minipage}\vspace{1mm}
 \par\noindent
 il primo comando acquisisce subito un read lock, e quindi non cambia nulla, ma
-se proviamo adesso a richidere un write lock che non potrà essere acquisito
+se proviamo adesso a richiedere un write lock che non potrà essere acquisito
 otterremo:
 
 \vspace{1mm}
@@ -1965,7 +2036,7 @@ Abbiamo visto come l'interfaccia POSIX per il file locking sia molto pi
 potente e flessibile di quella di BSD, questo comporta anche una maggiore
 complessità per via delle varie opzioni da passare a \func{fcntl}. Per questo
 motivo è disponibile anche una interfaccia semplificata (ripresa da System V)
-che utilizza la funzione \func{lockf}, il cui prototipo è:
+che utilizza la funzione \funcd{lockf}, il cui prototipo è:
 \begin{prototype}{sys/file.h}{int lockf(int fd, int cmd, off\_t len)}
   
   Applica, controlla o rimuove un \textit{file lock} sul file \param{fd}.
@@ -2005,7 +2076,7 @@ che specifica quale azione eseguire; i valori possibili sono riportati in
                       con un OR aritmetico dei valori.\\ 
     \hline    
   \end{tabular}
-  \caption{Valori possibili per il campo \var{cmd} di \func{lockf}.}
+  \caption{Valori possibili per l'argomento \param{cmd} di \func{lockf}.}
   \label{tab:file_lockf_type}
 \end{table}
 
@@ -2030,7 +2101,7 @@ opportune verifiche nei processi, questo verrebbe comunque rispettato.
 Per poter utilizzare il \textit{mandatory locking} è stato introdotto un
 utilizzo particolare del bit \acr{sgid}. Se si ricorda quanto esposto in
 \secref{sec:file_suid_sgid}), esso viene di norma utilizzato per cambiare il
-groupid effettivo con cui viene eseguito un programma, ed è pertanto sempre
+group-ID effettivo con cui viene eseguito un programma, ed è pertanto sempre
 associato alla presenza del permesso di esecuzione per il gruppo. Impostando
 questo bit su un file senza permesso di esecuzione in un sistema che supporta
 il \textit{mandatory locking}, fa sì che quest'ultimo venga attivato per il
@@ -2099,11 +2170,12 @@ lock\footnote{alcuni sistemi, come HP-UX, sono ancora pi
   comportamento non ha molto senso, dato che comunque qualunque accesso
   diretto al file è consentito.} in Linux è stata però fatta la scelta
 implementativa\footnote{per i dettagli si possono leggere le note relative
-  all'implementazione, mantenute insime ai sorgenti del kernel nel file
+  all'implementazione, mantenute insieme ai sorgenti del kernel nel file
   \file{Documentation/mandatory.txt}.}  di seguire questo comportamento
 soltanto quando si chiama \func{mmap} con l'opzione \const{MAP\_SHARED} (nel
 qual caso la funzione fallisce con il solito \errcode{EAGAIN}) che comporta la
 possibilità di modificare il file.
+\index{file!locking|)}