Una lunga serie di modifiche per tenere conto della riorganizzazione della
[gapil.git] / fileadv.tex
index 5203d17744dea60987154e798317d27c9a4391af..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\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.
+\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}\index{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.
+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{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
+\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}
@@ -94,9 +109,10 @@ funzione \funcd{select}, il cui prototipo 
     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}.
 }
@@ -111,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}
@@ -135,126 +151,249 @@ 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
+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 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.
+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 \funcd{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 \struct{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 \struct{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 \struct{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
@@ -262,77 +401,53 @@ vengono utilizzati solo per \var{revents} come valori in uscita).
   \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 \struct{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
-\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.
-  \end{errlist}
-  ed inoltre \errval{ENOMEM}.}
-\end{prototype}
-
-La funzione è sostanzialmente identica a \func{select}, solo che usa una
-struttura \struct{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\index{race condition} resta.} quando si
-deve eseguire un test su una variabile assegnata da un gestore 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\index{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
@@ -340,37 +455,49 @@ 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 \struct{siginfo\_t}, utilizzando la forma estesa
-\var{sa\_sigaction} del gestore (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
-gestore 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
@@ -386,29 +513,38 @@ 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 \const{SIGIO}, su cui si accumuleranno tutti i segnali
-in eccesso, e si dovrà determinare al solito modo quali sono i file diventati
+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\index{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.
+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, ed accessibile linkando i programmi con la
-libreria \file{librt}.  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 \struct{aiocb} (il cui nome sta per
@@ -421,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 \struct{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
@@ -460,31 +584,20 @@ 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;
-    void (*sigev_notify_function)(sigval_t);
-    pthread_attr_t *sigev_notify_attributes;
-};
-    \end{lstlisting}
+    \includestruct{listati/sigevent.h}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \struct{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}
 
@@ -493,7 +606,7 @@ 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}}
+\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 da \var{sigev\_signo}; se il gestore di
@@ -546,11 +659,11 @@ 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 \struct{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
@@ -580,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, \funcd{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}
@@ -608,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
 è:
@@ -729,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}
@@ -760,6 +876,16 @@ la notifica del completamento di tutte le richieste, impostando l'argomento
 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}
@@ -818,15 +944,10 @@ 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 \struct{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}
@@ -851,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}
@@ -872,17 +993,16 @@ 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 è \funcd{mmap}, che serve ad eseguire la mappatura
@@ -903,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).
@@ -1036,11 +1155,19 @@ 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.
+
+\begin{figure}[!htb]
+  \centering
+  \includegraphics[width=10cm]{img/mmap_boundary}
+  \caption{Schema della mappatura in memoria di una sezione di file di
+    dimensioni non corrispondenti al bordo di una pagina.}
+  \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
@@ -1055,15 +1182,6 @@ file non rientra nei confini di una pagina: in tal caso verr
 mappato su un segmento di memoria che si estende fino al bordo della pagina
 successiva.
 
-\begin{figure}[htb]
-  \centering
-  \includegraphics[width=10cm]{img/mmap_boundary}
-  \caption{Schema della mappatura in memoria di una sezione di file di
-    dimensioni non corrispondenti al bordo di una pagina.}
-  \label{fig:file_mmap_boundary}
-\end{figure}
-
-
 In questo caso è possibile accedere a quella zona di memoria che eccede le
 dimensioni specificate da \param{lenght}, senza ottenere un \const{SIGSEGV}
 poiché essa è presente nello spazio di indirizzi del processo, anche se non è
@@ -1078,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}
@@ -1267,10 +1385,11 @@ 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
@@ -1279,17 +1398,17 @@ In generale si distinguono due tipologie di \textit{file lock}:\footnote{di
   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
@@ -1323,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
-ottenere 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
@@ -1336,7 +1460,7 @@ 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
@@ -1411,7 +1535,7 @@ 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}
@@ -1512,18 +1636,10 @@ 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 \struct{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}
@@ -1546,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
@@ -1571,6 +1679,14 @@ il \acr{pid} del processo che detiene il lock.
   \label{tab:file_flock_type}
 \end{table}
 
+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
@@ -1717,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}.}