Alcune correzioni ai font dei link, e una trattazione esplicita
[gapil.git] / fileadv.tex
index 4737913a90046c33e7d9df43791a2242ebbaa9e9..1ba5b9990692a8489fe8deefd1f9c54124dd4964 100644 (file)
@@ -71,17 +71,18 @@ eseguire in continuazione delle system 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
+  multiplexing}, una nuova modalità di operazioni che consente 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
+l'esecuzione una volta che almeno una di quelle richieste sia effettuabile, 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 sez.~\ref{sec:TCP_sock_multiplexing}.
+ulteriori dettagli e qualche esempio di utilizzo concreto in
+sez.~\ref{sec:TCP_sock_multiplexing}.
 
 
 \subsection{Le funzioni \func{select} e \func{pselect}}
@@ -96,7 +97,7 @@ Il primo kernel unix-like ad introdurre una interfaccia per l'\textit{I/O
   \headdecl{sys/time.h}
   \headdecl{sys/types.h}
   \headdecl{unistd.h}
-  \funcdecl{int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set
+  \funcdecl{int select(int ndfs, fd\_set *readfds, fd\_set *writefds, fd\_set
     *exceptfds, struct timeval *timeout)}
   
   Attende che uno dei file descriptor degli insiemi specificati diventi
@@ -106,11 +107,11 @@ Il primo kernel unix-like ad introdurre una interfaccia per l'\textit{I/O
     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
+  \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}.
+  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+  \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
+    un valore non valido per \param{timeout}.
   \end{errlist}
   ed inoltre \errval{ENOMEM}.
 }
@@ -158,7 +159,9 @@ massimo, esso indica le dimensioni massime dei numeri usati nei \textit{file
   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.
+dar luogo a comportamenti non prevedibili; allo stesso modo usare
+\macro{FD\_SET} o \macro{FD\_CLR} con un file descriptor il cui valore eccede
+\const{FD\_SETSIZE} può dare luogo ad un comportamento indefinito.
 
 La funzione richiede di specificare tre insiemi distinti di file descriptor;
 il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
@@ -170,26 +173,25 @@ effettuare una lettura,\footnote{per essere precisi la funzione ritorner
   accadere che \func{select} riporti il relativo file descriptor come
   leggibile, ma una successiva \func{read} si blocchi.} il secondo,
 \param{writefds}, per verificare la possibilità effettuare una scrittura ed il
-terzo,
-\param{exceptfds}, per verificare l'esistenza di eccezioni (come i dati
+terzo, \param{exceptfds}, per verificare l'esistenza di eccezioni (come i dati
 urgenti \itindex{out-of-band} su un socket, vedi
 sez.~\ref{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
+specificare qual è il valore più alto fra i 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.
+necessaria. Questo limite viene indicato tramite l'argomento \param{ndfs}, che
+deve corrispondere al valore massimo aumentato di uno.\footnote{si ricordi che
+  i file descriptor sono numerati progressivamente a partire da zero, ed il
+  valore indica il numero più alto fra quelli da tenere sotto controllo;
+  dimenticarsi di aumentare di uno il valore di \param{ndfs} è 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
@@ -204,6 +206,15 @@ contenuto.
 
 \itindend{file~descriptor~set}
 
+Una volta ritornata la funzione si potrà controllare quali sono i file
+descriptor pronti ed operare su di essi, si tenga presente però che si tratta
+solo di un suggerimento, esistono infatti condizioni\footnote{ad esempio
+  quando su un socket arrivano dei dati che poi vengono scartati perché
+  corrotti.} in cui \func{select} può riportare in maniera spuria che un file
+descriptor è pronto in lettura, quando una successiva lettura si bloccherebbe.
+Per questo quando si usa \textit{I/O multiplexing} è sempre raccomandato l'uso
+delle funzioni di lettura e scrittura in modalità non bloccante.
+
 In Linux \func{select} modifica anche il valore di \param{timeout},
 impostandolo al tempo restante in caso di interruzione prematura; questo è
 utile quando la funzione viene interrotta da un segnale, in tal caso infatti
@@ -218,10 +229,10 @@ rimanente.\footnote{questo pu
 
 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ò
+controllo.  Infatti il kernel riceve con \param{ndfs} un limite 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 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
@@ -256,11 +267,11 @@ precedenti, ed inoltre aggiunge a \func{select} una nuova funzione
     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
+  \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}.
+  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+  \item[\errcode{EINVAL}] si è specificato per \param{ndfs} un valore negativo
+    un valore non valido per \param{timeout}.
   \end{errlist}
   ed inoltre \errval{ENOMEM}.}
 \end{prototype}
@@ -305,7 +316,7 @@ contestualmente all'esecuzione della funzione,\footnote{in Linux per
   kernel 2.6.16, non era presente la relativa system call, e la funzione era
   implementata nelle \acr{glibc} attraverso \func{select} (vedi \texttt{man
     select\_tut}) per cui la possibilità di \itindex{race~condition}
-  \textit{race condition} permaneva; in tale situzione si può ricorrere ad una
+  \textit{race condition} permaneva; in tale situazione si può ricorrere ad una
   soluzione alternativa, chiamata \itindex{self-pipe trick} \textit{self-pipe
     trick}, che consiste nell'aprire una pipe (vedi sez.~\ref{sec:ipc_pipes})
   ed usare \func{select} sul capo in lettura della stessa; si può indicare
@@ -339,10 +350,10 @@ cui prototipo 
     in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
     ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
-  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
+  \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}] Il valore di \param{nfds} eccede il limite
+  \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}.}
@@ -357,17 +368,6 @@ indica un'attesa indefinita, mentre un valore nullo 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}
-    \includestruct{listati/pollfd.h}
-  \end{minipage} 
-  \normalsize 
-  \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 inizializzata una struttura
 \struct{pollfd} nel vettore indicato dall'argomento \param{ufds}.  La
 struttura, la cui definizione è riportata in fig.~\ref{fig:file_pollfd},
@@ -381,6 +381,17 @@ 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.
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/pollfd.h}
+  \end{minipage} 
+  \normalsize 
+  \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}
+
 Le costanti che definiscono i valori relativi ai bit usati nelle maschere
 binarie dei campi \var{events} e \var{revents} sono riportati in
 tab.~\ref{tab:file_pollfd_flags}, insieme al loro significato. Le si sono
@@ -399,13 +410,13 @@ nel campo \var{revents} per notificare delle condizioni di errore.
     \hline
     \const{POLLIN}    & È possibile la lettura.\\
     \const{POLLRDNORM}& Sono disponibili in lettura dati normali.\\ 
-    \const{POLLRDBAND}& Sono disponibili in lettura dati prioritari. \\
+    \const{POLLRDBAND}& Sono disponibili in lettura dati prioritari.\\
     \const{POLLPRI}   & È possibile la lettura di \itindex{out-of-band} dati
                         urgenti.\\ 
     \hline
     \const{POLLOUT}   & È possibile la scrittura immediata.\\
-    \const{POLLWRNORM}& È possibile la scrittura di dati normali.  \\ 
-    \const{POLLWRBAND}& È possibile la scrittura di dati prioritari. \\
+    \const{POLLWRNORM}& È possibile la scrittura di dati normali.\\ 
+    \const{POLLWRBAND}& È possibile la scrittura di dati prioritari.\\
     \hline
     \const{POLLERR}   & C'è una condizione di errore.\\
     \const{POLLHUP}   & Si è verificato un hung-up.\\
@@ -444,11 +455,30 @@ valore nullo indica che si 
 indica un errore nella chiamata, il cui codice viene riportato al solito
 tramite \var{errno}.
 
+L'uso di \func{poll} consente di superare alcuni dei problemi illustrati in
+precedenza per \func{select}; anzitutto, dato che in questo caso si usa un
+vettore di strutture \struct{pollfd} di dimensione arbitraria, non esiste il
+limite introdotto dalle dimensioni massime di un \itindex{file~descriptor~set}
+\textit{file descriptor set} e la dimensione dei dati passati al kernel
+dipende solo dal numero dei file descriptor che si vogliono controllare, non
+dal loro valore.\footnote{anche se usando dei bit un \textit{file descriptor
+    set} può essere più efficiente di un vettore di strutture \struct{pollfd},
+  qualora si debba osservare un solo file descriptor con un valore molto alto
+  ci si troverà ad utilizzare inutilmente un maggiore quantitativo di
+  memoria.} 
+
+Inoltre con \func{select} lo stesso \itindex{file~descriptor~set} \textit{file
+  descriptor set} è usato sia in ingresso che in uscita, e questo significa
+che tutte le volte che si vuole ripetere l'operazione occorre reinizializzarlo
+da capo. Questa operazione, che può essere molto onerosa se i file descriptor
+da tenere sotto osservazione sono molti, non è invece necessaria con
+\func{poll}.
+
 Abbiamo visto in sez.~\ref{sec:file_select} come lo standard POSIX preveda una
 variante di \func{select} che consente di gestire correttamente la ricezione
 dei segnali nell'attesa su un file descriptor.  Con l'introduzione di una
 implementazione reale di \func{pselect} nel kernel 2.6.16, è stata aggiunta
-anche una analoga funzione che svolga lo stesso ruolo per \func{poll}. 
+anche una analoga funzione che svolga lo stesso ruolo per \func{poll}.
 
 In questo caso si tratta di una estensione che è specifica di Linux e non è
 prevista da nessuno standard; essa può essere utilizzata esclusivamente se si
@@ -466,10 +496,10 @@ prototipo 
     in caso di successo, o 0 se c'è stato un timeout e -1 in caso di errore,
     ed in quest'ultimo caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
-  \item[\errcode{EBADF}] Si è specificato un file descriptor sbagliato in uno
+  \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}] Il valore di \param{nfds} eccede il limite
+  \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}.}
@@ -489,13 +519,380 @@ puntatore ad una struttura \struct{timespec}, gli altri argomenti comuni con
 risultati illustrati in precedenza.
 
 
-% TODO accennare a ppoll vedi articolo LWN http://lwn.net/Articles/176750/
+\subsection{L'interfaccia di \textit{epoll}}
+\label{sec:file_epoll}
+
+\itindbeg{epoll}
+
+Nonostante \func{poll} presenti alcuni vantaggi rispetto a \func{select},
+anche questa funzione non è molto efficiente quando deve essere utilizzata con
+un gran numero di file descriptor,\footnote{in casi del genere \func{select}
+  viene scartata a priori, perché può avvenire che il numero di file
+  descriptor ecceda le dimensioni massime di un \itindex{file~descriptor~set}
+  \textit{file descriptor set}.} in particolare nel caso in cui solo pochi di
+questi diventano attivi. Il problema in questo caso è che il tempo impiegato
+da \func{poll} a trasferire i dati da e verso il kernel è proporzionale al
+numero di file descriptor osservati, non a quelli che presentano attività.
+
+Quando ci sono decine di migliaia di file descriptor osservati e migliaia di
+eventi al secondo,\footnote{il caso classico è quello di un server web di un
+  sito con molti accessi.} l'uso di \func{poll} comporta la necessità di
+trasferire avanti ed indietro da user space a kernel space la lunga lista
+delle strutture \struct{pollfd} migliaia di volte al secondo. A questo poi si
+aggiunge il fatto che la maggior parte del tempo di esecuzione sarà 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. In una situazione come questa l'uso delle funzioni classiche
+dell'interfaccia dell'\textit{I/O multiplexing} viene a costituire un collo di
+bottiglia che degrada irrimediabilmente le prestazioni.
+
+Per risolvere questo tipo di situazioni sono state ideate delle interfacce
+specialistiche\footnote{come \texttt{/dev/poll} in Solaris, o \texttt{kqueue}
+  in BSD.} il cui scopo fondamentale è quello di restituire solamente le
+informazioni relative ai file descriptor osservati che presentano una
+attività, evitando così le problematiche appena illustrate. In genere queste
+prevedono che si registrino una sola volta i file descriptor da tenere sotto
+osservazione, e forniscono un meccanismo che notifica quali di questi
+presentano attività.
+
+Le modalità con cui avviene la notifica sono due, la prima è quella classica
+(quella usata da \func{poll} e \func{select}) che viene chiamata \textit{level
+  triggered}.\footnote{la nomenclatura è stata introdotta da Jonathan Lemon in
+  un articolo su \texttt{kqueue} al BSDCON 2000, e deriva da quella usata
+  nell'elettronica digitale.} In questa modalità vengono notificati i file
+descriptor che sono \textsl{pronti} per l'operazione richiesta, e questo
+avviene indipendentemente dalle operazioni che possono essere state fatte su
+di essi a partire dalla precedente notifica.  Per chiarire meglio il concetto
+ricorriamo ad un esempio: se su un file descriptor sono diventati disponibili
+in lettura 2000 byte ma dopo la notifica ne sono letti solo 1000 (ed è quindi
+possibile eseguire una ulteriore lettura dei restanti 1000), in modalità
+\textit{level triggered} questo sarà nuovamente notificato come
+\textsl{pronto}.
+
+La seconda modalità, è detta \textit{edge triggered}, e prevede che invece
+vengano notificati solo i file descriptor che hanno subito una transizione da
+\textsl{non pronti} a \textsl{pronti}. Questo significa che in modalità
+\textit{edge triggered} nel caso del precedente esempio il file descriptor
+diventato pronto da cui si sono letti solo 1000 byte non verrà nuovamente
+notificato come pronto, nonostante siano ancora disponibili in lettura 1000
+byte. Solo una volta che si saranno esauriti tutti i byte disponibili, e che
+il file descriptor sia tornato non essere pronto, si potrà ricevere una
+ulteriore notifica qualora ritornasse pronto.
+
+Nel caso di Linux al momento la sola interfaccia che fornisce questo tipo di
+servizio è \textit{epoll},\footnote{l'interfaccia è stata creata da Davide
+  Libenzi, ed è stata introdotta per la prima volta nel kernel 2.5.44, ma la
+  sua forma definitiva è stata raggiunta nel kernel 2.5.66.} anche se sono in
+discussione altre interfacce con le quali si potranno effettuare lo stesso
+tipo di operazioni;\footnote{al momento della stesura di queste note (Giugno
+  2007) un'altra interfaccia proposta è quella di \textit{kevent}, che
+  fornisce un sistema di notifica di eventi generico in grado di fornire le
+  stesse funzionalità di \textit{epoll}, esiste però una forte discussione
+  intorno a tutto ciò e niente di definito.}  \textit{epoll} è in grado di
+operare sia in modalità \textit{level triggered} che \textit{edge triggered}.
+
+La prima versione \textit{epoll} prevedeva l'apertura di uno speciale file di
+dispositivo, \texttt{/dev/epoll}, per ottenere un file descriptor da
+utilizzare con le funzioni dell'interfaccia,\footnote{il backporting
+  dell'interfaccia per il kernel 2.4, non ufficiale, utilizza sempre questo
+  file.} ma poi si è passati all'uso una apposita \textit{system call}.  Il
+primo passo per usare l'interfaccia di \textit{epoll} è pertanto quello di
+chiamare la funzione \funcd{epoll\_create}, il cui prototipo è:
+\begin{prototype}{sys/epoll.h}
+  {int epoll\_create(int size)}
+  
+  Apre un file descriptor per \textit{epoll}.
+  
+  \bodydesc{La funzione restituisce un file descriptor in caso di successo, o
+    $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EINVAL}] si è specificato un valore di \param{size} non
+    positivo.
+  \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti
+    nel sistema.
+  \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare
+    l'istanza.
+  \end{errlist}
+}
+\end{prototype}
+
+La funzione restituisce un file descriptor speciale,\footnote{esso non è
+  associato a nessun file su disco, inoltre a differenza dei normali file
+  descriptor non può essere inviato ad un altro processo attraverso un socket
+  locale (vedi sez.~\ref{sec:sock_fd_passing}).} detto anche \textit{epoll
+  descriptor}, che viene associato alla infrastruttura utilizzata dal kernel
+per gestire la notifica degli eventi; l'argomento \param{size} serve a dare
+l'indicazione del numero di file descriptor che si vorranno tenere sotto
+controllo, ma costituisce solo un suggerimento per semplificare l'allocazione
+di risorse sufficienti, non un valore massimo.
+
+Una volta ottenuto un file descriptor per \textit{epoll} il passo successivo è
+indicare quali file descriptor mettere sotto osservazione e quali operazioni
+controllare, per questo si deve usare la seconda funzione dell'interfaccia,
+\funcd{epoll\_ctl}, il cui prototipo è:
+\begin{prototype}{sys/epoll.h}
+  {int epoll\_ctl(int epfd, int op, int fd, struct epoll\_event *event)}
+  
+  Esegue le operazioni di controllo di \textit{epoll}.
+  
+  \bodydesc{La funzione restituisce $0$ in caso di successo o $-1$ in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] il file descriptor \param{epfd} o \param{fd} non sono
+    validi.
+  \item[\errcode{EEXIST}] l'operazione richiesta è \const{EPOLL\_CTL\_ADD} ma
+    \param{fd} è già stato inserito in \param{epfd}.
+  \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
+    con \func{epoll\_create}, o \param{fd} è lo stesso \param{epfd} o
+    l'operazione richiesta con \param{op} non è supportata.
+  \item[\errcode{ENOENT}] l'operazione richiesta è \const{EPOLL\_CTL\_MOD} o
+    \const{EPOLL\_CTL\_DEL} ma \param{fd} non è inserito in \param{epfd}.
+  \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel gestire
+    l'operazione richiesta.
+  \item[\errcode{EPERM}] il file \param{fd} non supporta \textit{epoll}.
+  \end{errlist}
+}
+\end{prototype}
+
+Il comportamento della funzione viene controllato dal valore dall'argomento
+\param{op} che consente di specificare quale operazione deve essere eseguita.
+Le costanti che definiscono i valori utilizzabili per \param{op}
+sono riportate in tab.~\ref{tab:epoll_ctl_operation}, assieme al significato
+delle operazioni cui fanno riferimento.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{8cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{EPOLL\_CTL\_ADD}& Aggiunge un nuovo file descriptor da osservare
+                             \param{fd} alla lista dei file descriptor
+                             controllati tramite \param{epfd}, in
+                             \param{event} devono essere specificate le
+                             modalità di osservazione.\\
+    \const{EPOLL\_CTL\_MOD}& Modifica le modalità di osservazione del file
+                             descriptor \param{fd} secondo il contenuto di
+                             \param{event}.\\
+    \const{EPOLL\_CTL\_DEL}& Rimuove il file descriptor \param{fd} dalla lista
+                             dei file controllati tramite \param{epfd}.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{op} che consentono di scegliere quale
+    operazione di controllo effettuare con la funzione \func{epoll\_ctl}.} 
+  \label{tab:epoll_ctl_operation}
+\end{table}
+
+La funzione prende sempre come primo argomento un file descriptor di
+\textit{epoll}, \param{epfd}, che deve essere stato ottenuto in precedenza con
+una chiamata a \func{epoll\_create}. L'argomento \param{fd} indica invece il
+file descriptor che si vuole tenere sotto controllo, quest'ultimo può essere
+un qualunque file descriptor utilizzabile con \func{poll}, ed anche un altro
+file descriptor di \textit{epoll}, ma non lo stesso \param{epfd}.
+
+L'ultimo argomento, \param{event}, deve essere un puntatore ad una struttura
+di tipo \struct{epoll\_event}, ed ha significato solo con le operazioni
+\const{EPOLL\_CTL\_MOD} e \const{EPOLL\_CTL\_ADD}, per le quali serve ad
+indicare quale tipo di evento relativo ad \param{fd} si vuole che sia tenuto
+sotto controllo.  L'argomento viene ignorato con l'operazione
+\const{EPOLL\_CTL\_DEL}.\footnote{fino al kernel 2.6.9 era comunque richiesto
+  che questo fosse un puntatore valido, anche se poi veniva ignorato, a
+  partire dal 2.6.9 si può specificare anche un valore \texttt{NULL}.}
+
+
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/epoll_event.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{epoll\_event}, che consente di specificare
+    gli eventi associati ad un file descriptor controllato con
+    \textit{epoll}.}
+  \label{fig:epoll_event}
+\end{figure}
+
+La struttura \struct{epoll\_event} è l'analoga di \struct{pollfd} e come
+quest'ultima serve sia in ingresso (quando usata con \func{epoll\_ctl}) ad
+impostare quali eventi osservare, che in uscita (nei risultati ottenuti con
+\func{epoll\_wait}) per ricevere le notifiche degli eventi avvenuti.  La sua
+definizione è riportata in fig.~\ref{fig:epoll_event}. 
+
+Il primo campo, \var{events}, è una maschera binaria in cui ciascun bit
+corrisponde o ad un tipo di evento, o una modalità di notifica; detto campo
+deve essere specificato come OR aritmetico delle costanti riportate in
+tab.~\ref{tab:epoll_events}. Il secondo campo, \var{data}, serve ad indicare a
+quale file descriptor si intende fare riferimento, ed in astratto può
+contenere un valore qualsiasi che permetta di identificarlo, di norma comunque
+si usa come valore lo stesso \param{fd}.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{8cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{EPOLLIN}     & Il file è pronto per le operazioni di lettura
+                          (analogo di \const{POLLIN}).\\
+    \const{EPOLLOUT}    & Il file è pronto per le operazioni di scrittura
+                          (analogo di \const{POLLOUT}).\\
+    \const{EPOLLRDHUP}  & L'altro capo di un socket di tipo
+                          \const{SOCK\_STREAM} (vedi sez.~\ref{sec:sock_type})
+                          ha chiuso la connessione o il capo in scrittura
+                          della stessa (vedi sez.~\ref{sec:TCP_shutdown}).\\
+    \const{EPOLLPRI}    & Ci sono \itindex{out-of-band} dati urgenti
+                          disponibili in lettura (analogo di
+                          \const{POLLPRI}); questa condizione viene comunque
+                          riportata in uscita, e non è necessaria impostarla
+                          in ingresso.\\ 
+    \const{EPOLLERR}    & Si è verificata una condizione di errore 
+                          (analogo di \const{POLLERR}); questa condizione
+                          viene comunque riportata in uscita, e non è
+                          necessaria impostarla in ingresso.\\
+    \const{EPOLLHUP}    & Si è verificata una condizione di hung-up.\\
+    \const{EPOLLET}     & Imposta la notifica in modalità \textit{edge
+                            triggered} per il file descriptor associato.\\ 
+    \const{EPOLLONESHOT}& Imposta la modalità \textit{one-shot} per il file
+                          descriptor associato.\footnotemark\\
+    \hline    
+  \end{tabular}
+  \caption{Costanti che identificano i bit del campo \param{events} di
+    \struct{epoll\_event}.}
+  \label{tab:epoll_events}
+\end{table}
+
+\footnotetext{questa modalità è disponibile solo a partire dal kernel 2.6.2.}
+
+Le modalità di utilizzo di \textit{epoll} prevedano che si definisca qual'è
+l'insieme dei file descriptor da tenere sotto controllo tramite un certo
+\textit{epoll descriptor} \param{epfd} attraverso una serie di chiamate a
+\const{EPOLL\_CTL\_ADD}.\footnote{un difetto dell'interfaccia è che queste
+  chiamate devono essere ripetute per ciascun file descriptor, incorrendo in
+  una perdita di prestazioni qualora il numero di file descriptor sia molto
+  grande; per questo è stato proposto di introdurre come estensione una
+  funzione \func{epoll\_ctlv} che consenta di effettuare con una sola chiamata
+  le impostazioni per un blocco di file descriptor.} L'uso di
+\const{EPOLL\_CTL\_MOD} consente in seguito di modificare le modalità di
+osservazione di un file descriptor che sia già stato aggiunto alla lista di
+osservazione.
+
+Le impostazioni di default prevedono che la notifica degli eventi richiesti
+sia effettuata in modalità \textit{level triggered}, a meno che sul file
+descriptor non si sia impostata la modalità \textit{edge triggered},
+registrandolo con \const{EPOLLET} attivo nel campo \var{events}.  Si tenga
+presente che è possibile tenere sotto osservazione uno stesso file descriptor
+su due \textit{epoll descriptor} diversi, ed entrambi riceveranno le
+notifiche, anche se questa pratica è sconsigliata.
+
+Qualora non si abbia più interesse nell'osservazione di un file descriptor lo
+si può rimuovere dalla lista associata a \param{epfd} con
+\const{EPOLL\_CTL\_DEL}; si tenga conto inoltre che i file descriptor sotto
+osservazione che vengono chiusi sono eliminati dalla lista automaticamente e
+non è necessario usare \const{EPOLL\_CTL\_DEL}.
+
+Infine una particolare modalità di notifica è quella impostata con
+\const{EPOLLONESHOT}: a causa dell'implementazione di \textit{epoll} infatti
+quando si è in modalità \textit{edge triggered} l'arrivo in rapida successione
+di dati in blocchi separati\footnote{questo è tipico con i socket di rete, in
+  quanto i dati arrivano a pacchetti.} può causare una generazione di eventi
+(ad esempio segnalazioni di dati in lettura disponibili) anche se la
+condizione è già stata rilevata.\footnote{si avrebbe cioè una rottura della
+  logica \textit{edge triggered}.} 
+
+Anche se la situazione è facile da gestire, la si può evitare utilizzando
+\const{EPOLLONESHOT} per impostare la modalità \textit{one-shot}, in cui la
+notifica di un evento viene effettuata una sola volta, dopo di che il file
+descriptor osservato, pur restando nella lista di osservazione, viene
+automaticamente disattivato,\footnote{la cosa avviene contestualmente al
+  ritorno di \func{epoll\_wait} a causa dell'evento in questione.} e per
+essere riutilizzato dovrà essere riabilitato esplicitamente con una successiva
+chiamata con \const{EPOLL\_CTL\_MOD}.
+
+Una volta impostato l'insieme di file descriptor che si vogliono osservare con
+i relativi eventi, la funzione che consente di attendere l'occorrenza di uno
+di tali eventi è \funcd{epoll\_wait}, il cui prototipo è:
+\begin{prototype}{sys/epoll.h}
+  {int epoll\_wait(int epfd, struct epoll\_event * events, int maxevents, int
+    timeout)}
+  
+  Attende che uno dei file descriptor osservati sia pronto.
+  
+  \bodydesc{La funzione restituisce il numero di file descriptor pronti in
+    caso di successo o $-1$ in caso di errore, nel qual caso \var{errno}
+    assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] il file descriptor \param{epfd} non è valido.
+  \item[\errcode{EFAULT}] il puntatore \param{events} non è valido.
+  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima
+    della scadenza di \param{timeout}.
+  \item[\errcode{EINVAL}] il file descriptor \param{epfd} non è stato ottenuto
+    con \func{epoll\_create}, o \param{maxevents} non è maggiore di zero.
+  \end{errlist}
+}
+\end{prototype}
+
+La funzione si blocca in attesa di un evento per i file descriptor registrati
+nella lista di osservazione di \param{epfd} fino ad un tempo massimo
+specificato in millisecondi tramite l'argomento \param{timeout}. Gli eventi
+registrati vengono riportati in un vettore di strutture \struct{epoll\_event}
+(che deve essere stato allocato in precedenza) all'indirizzo indicato
+dall'argomento \param{events}, fino ad un numero massimo di eventi impostato
+con l'argomento \param{maxevents}.
+
+La funzione ritorna il numero di eventi rilevati, o un valore nullo qualora
+sia scaduto il tempo massimo impostato con \param{timeout}. Per quest'ultimo,
+oltre ad un numero di millisecondi, si può utilizzare il valore nullo, che
+indica di non attendere e ritornare immediatamente,\footnote{anche in questo
+  caso il valore di ritorno sarà nullo.} o il valore $-1$, che indica
+un'attesa indefinita. L'argomento \param{maxevents} dovrà invece essere sempre
+un intero positivo.
+
+Come accennato la funzione restituisce i suoi risultati nel vettore di
+strutture \struct{epoll\_event} puntato da \param{events}; in tal caso nel
+campo \param{events} di ciascuna di esse saranno attivi i flag relativi agli
+eventi accaduti, mentre nel campo \var{data} sarà restituito il valore che era
+stato impostato per il file descriptor per cui si è verificato l'evento quando
+questo era stato registrato con le operazioni \const{EPOLL\_CTL\_MOD} o
+\const{EPOLL\_CTL\_ADD}, in questo modo il campo \var{data} consente di
+identificare il file descriptor.\footnote{ed è per questo che, come accennato,
+  è consuetudine usare per \var{data} il valore del file descriptor stesso.}
+
+Si ricordi che le occasioni per cui \func{epoll\_wait} ritorna dipendono da
+come si è impostata la modalità di osservazione (se \textit{level triggered} o
+\textit{edge triggered}) del singolo file descriptor. L'interfaccia assicura
+che se arrivano più eventi fra due chiamate successive ad \func{epoll\_wait}
+questi vengano combinati. Inoltre qualora su un file descriptor fossero
+presenti eventi non ancora notificati, e si effettuasse una modifica
+dell'osservazione con \const{EPOLL\_CTL\_MOD} questi verrebbero riletti alla
+luce delle modifiche.
+
+Si tenga presente infine che con l'uso della modalità \textit{edge triggered}
+il ritorno di \func{epoll\_wait} indica un file descriptor è pronto e resterà
+tale fintanto che non si sono completamente esaurite le operazioni su di esso.
+Questa condizione viene generalmente rilevata dall'occorrere di un errore di
+\errcode{EAGAIN} al ritorno di una \func{read} o una \func{write},\footnote{è
+  opportuno ricordare ancora una volta che l'uso dell'I/O multiplexing
+  richiede di operare sui file in modalità non bloccante.} ma questa non è la
+sola modalità possibile, ad esempio la condizione può essere riconosciuta
+anche con il fatto che sono stati restituiti meno dati di quelli richiesti.
+
+Come le precedenti \func{select} e \func{poll}, le funzioni dell'interfaccia
+di \textit{epoll} vengono utilizzate prevalentemente con i server di rete,
+quando si devono tenere sotto osservazione un gran numero di socket; per
+questo motivo rimandiamo di nuovo la trattazione di un esempio concreto a
+quando avremo esaminato in dettaglio le caratteristiche dei socket, in
+particolare si potrà trovare un programma che utilizza questa interfaccia in
+sez.~\ref{sec:TCP_sock_multiplexing}.
+
+
+\itindend{epoll}
 
-%\subsection{L'interfaccia di \textit{epoll}}
-%\label{sec:file_epoll}
-% placeholder ...
 
-% TODO epoll 
 
 \section{L'accesso \textsl{asincrono} ai file}
 \label{sec:file_asyncronous_access}
@@ -508,46 +905,52 @@ contesto le modalit
 \textsl{asincrona}, quelle cioè in cui un processo non deve bloccarsi in
 attesa della disponibilità dell'accesso al file, ma può proseguire
 nell'esecuzione utilizzando invece un meccanismo di notifica asincrono (di
-norma un segnale), per essere avvisato della possibilità di eseguire le
+norma un segnale, ma esistono anche altre interfacce, come \itindex{inotify}
+\textit{inotify}), per essere avvisato della possibilità di eseguire le
 operazioni di I/O volute.
 
 
-\subsection{Operazioni asincrone sui file}
+\subsection{Il \textit{Signal driven I/O}}
 \label{sec:file_asyncronous_operation}
 
-Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso l'uso
-del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e dei
-  comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è specifico
-  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
-sez.~\ref{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
-sez.~\ref{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 in questo caso è 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},
+Abbiamo accennato in sez.~\ref{sec:file_open} che è possibile, attraverso
+l'uso del flag \const{O\_ASYNC},\footnote{l'uso del flag di \const{O\_ASYNC} e
+  dei comandi \const{F\_SETOWN} e \const{F\_GETOWN} per \func{fcntl} è
+  specifico 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
+sez.~\ref{sec:file_fcntl}).
+
+In realtà parlare di apertura in modalità asincrona non significa che le
+operazioni di lettura o scrittura del file vengono eseguite in modo asincrono
+(tratteremo questo, che è ciò che più propriamente viene chiamato \textsl{I/O
+  asincrono}, in sez.~\ref{sec:file_asyncronous_io}), quanto dell'attivazione
+un meccanismo di notifica asincrona delle variazione dello stato del file
+descriptor aperto in questo modo.  Quello che succede in questo caso è 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à.\footnote{questa modalità non è utilizzabile con i file
+  ordinari ma solo con socket, file di terminale o pseudo terminale, e, a
+  partire dal kernel 2.6, anche per fifo e pipe.}
+
+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 di I/O in risposta alla ricezione del segnale non ci
 sarà più la necessità di restare bloccati in attesa della disponibilità di
-accesso ai file; per questo motivo Stevens chiama questa modalità
-\textit{signal driven I/O}.
-
-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. % TODO 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.
+accesso ai file. 
+
+Per questo motivo Stevens, ed anche le pagine di manuale di
+Linux, chiamano questa modalità ``\textit{Signal driven I/O}''.  Questa è
+ancora un'altra modalità di gestione dell'I/O, alternativa all'uso di
+\itindex{epoll} \textit{epoll},\footnote{anche se le prestazioni ottenute con
+  questa tecnica sono inferiori, il vantaggio è che questa modalità è
+  utilizzabile anche con kernel che non supportano \textit{epoll}, come quelli
+  della serie 2.4, ottenendo comunque prestazioni superiori a quelle che si
+  hanno con \func{poll} e \func{select}.} che consente di evitare l'uso delle
+funzioni \func{poll} o \func{select} che, come illustrato in
+sez.~\ref{sec:file_epoll}, quando vengono usate con un numero molto grande di
+file descriptor, non hanno buone prestazioni.
 
 Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
 presenta notevoli problemi, dato che non è possibile determinare, quando i
@@ -585,11 +988,16 @@ un file su cui l'accesso 
 funzioni come \func{poll} e \func{select}, almeno fintanto che non si satura
 la coda.  
 
-Se infatti si  eccedono le dimensioni di quest'ultima,  il kernel, non potendo
-più assicurare il comportamento corretto  per un segnale real-time, invierà al
-suo posto un solo \const{SIGIO}, su  cui si saranno accumulati tutti i segnali
-in  eccesso, e si  dovrà allora  determinare con  un ciclo  quali sono  i file
-diventati attivi.
+Se infatti si eccedono le dimensioni di quest'ultima, il kernel, non potendo
+più assicurare il comportamento corretto per un segnale real-time, invierà al
+suo posto un solo \const{SIGIO}, su cui si saranno accumulati tutti i segnali
+in eccesso, e si dovrà allora determinare con un ciclo quali sono i file
+diventati attivi. L'unico modo per essere sicuri che questo non avvenga è di
+impostare la lunghezza della coda dei segnali real-time ad una dimensione
+identica al valore massimo del numero di file descriptor
+utilizzabili.\footnote{vale a dire impostare il contenuto di
+  \procfile{/proc/sys/kernel/rtsig-max} allo stesso valore del contenuto di
+  \procfile{/proc/sys/fs/file-max}.}
 
 % TODO fare esempio che usa O_ASYNC
 
@@ -603,27 +1011,29 @@ risposta\footnote{o meglio la non risposta, tanto che questa nelle Unix FAQ
   \cite{UnixFAQ} viene anche chiamata una \textit{Frequently Unanswered
     Question}.} è che nell'architettura classica di Unix questo non è
 possibile. Al contrario di altri sistemi operativi infatti un kernel unix-like
-non prevede alcun meccanismo per cui un processo possa essere
+classico non prevedeva alcun meccanismo per cui un processo possa essere
 \textsl{notificato} di eventuali modifiche avvenute su un file. Questo è il
 motivo per cui i demoni devono essere \textsl{avvisati} in qualche
 modo\footnote{in genere questo vien fatto inviandogli un segnale di
-  \const{SIGHUP} che, per convenzione adottata dalla gran parte di detti
+  \const{SIGHUP} che, per una convenzione adottata dalla gran parte di detti
   programmi, causa la rilettura della configurazione.} se il loro file di
 configurazione è stato modificato, perché possano rileggerlo e riconoscere le
 modifiche.
 
 Questa scelta è stata fatta perché provvedere un simile meccanismo a livello
-generale comporterebbe un notevole aumento di complessità dell'architettura
-della gestione dei file, per fornire una funzionalità necessaria soltanto in
-casi particolari. Dato che all'origine di Unix i soli programmi che potevano
-avere una tale esigenza erano i demoni, attenendosi a uno dei criteri base
-della progettazione, che era di far fare al kernel solo le operazioni
-strettamente necessarie e lasciare tutto il resto a processi in user space,
-non era stata prevista nessuna funzionalità di notifica.
+generico per qualunque file comporterebbe un notevole aumento di complessità
+dell'architettura della gestione dei file, il tutto per fornire una
+funzionalità che serve soltanto in alcuni casi particolari. Dato che
+all'origine di Unix i soli programmi che potevano avere una tale esigenza
+erano i demoni, attenendosi a uno dei criteri base della progettazione, che
+era di far fare al kernel solo le operazioni strettamente necessarie e
+lasciare tutto il resto a processi in user space, non era stata prevista
+nessuna funzionalità di notifica.
 
 Visto però il crescente interesse nei confronti di una funzionalità di questo
-tipo (molto richiesta specialmente nello sviluppo dei programmi ad interfaccia
-grafica) sono state successivamente introdotte delle estensioni che
+tipo, che è molto richiesta specialmente nello sviluppo dei programmi ad
+interfaccia grafica, quando si deve presentare all'utente lo stato del
+filesystem, sono state successivamente introdotte delle estensioni che
 permettessero la creazione di meccanismi di notifica più efficienti dell'unica
 soluzione disponibile con l'interfaccia tradizionale, che è quella del
 \itindex{polling} \textit{polling}.
@@ -735,7 +1145,7 @@ operazione di lettura, declassando il \textit{lease} a lettura con
 
 Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
 il numero di secondi specificato dal parametro di sistema mantenuto in
-\file{/proc/sys/fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
+\procfile{/proc/sys/fs/lease-break-time} sarà il kernel stesso a rimuoverlo (o
 declassarlo) automaticamente.\footnote{questa è una misura di sicurezza per
   evitare che un processo blocchi indefinitamente l'accesso ad un file
   acquisendo un \textit{lease}.} Una volta che un \textit{lease} è stato
@@ -752,13 +1162,19 @@ risolvere il problema di rilevare automaticamente quando un file o una
 directory vengono modificati, che è quanto necessario ad esempio ai programma
 di gestione dei file dei vari desktop grafici.
 
-Per risolvere questo problema è stata allora creata un'altra interfaccia,
-chiamata \textit{dnotify}, che consente di richiedere una notifica quando una
-directory, o di uno qualunque dei file in essa contenuti, viene modificato.
-Come per i \textit{file lease} la notifica avviene di default attraverso il
-segnale \const{SIGIO}, ma se ne può utilizzare un altro. inoltre si potrà
-ottenere nel gestore del segnale il file descriptor che è stato modificato
-tramite il contenuto della struttura \struct{siginfo\_t}.
+Per risolvere questo problema a partire dal kernel 2.4 è stata allora creata
+un'altra interfaccia,\footnote{si ricordi che anche questa è una interfaccia
+  specifica di Linux che deve essere evitata se si vogliono scrivere programmi
+  portabili, e che le funzionalità illustrate sono disponibili soltanto se è
+  stata definita la macro \macro{\_GNU\_SOURCE}.} chiamata \textit{dnotify},
+che consente di richiedere una notifica quando una directory, o uno qualunque
+dei file in essa contenuti, viene modificato.  Come per i \textit{file lease}
+la notifica avviene di default attraverso il segnale \const{SIGIO}, ma se ne
+può utilizzare un altro.\footnote{e di nuovo, per le ragioni già esposte in
+  precedenza, è opportuno che si utilizzino dei segnali real-time.} Inoltre,
+come in precedenza, si potrà ottenere nel gestore del segnale il file
+descriptor che è stato modificato tramite il contenuto della struttura
+\struct{siginfo\_t}.
 
 \index{file!lease|)}
 
@@ -788,7 +1204,7 @@ tramite il contenuto della struttura \struct{siginfo\_t}.
     \const{DN\_ATTRIB} & È stato modificato un attributo di un file con
                          l'esecuzione di una fra \func{chown}, \func{chmod},
                          \func{utime}.\\ 
-    \const{DN\_MULTISHOT}& richiede una notifica permanente di tutti gli
+    \const{DN\_MULTISHOT}& Richiede una notifica permanente di tutti gli
                          eventi.\\ 
     \hline    
   \end{tabular}
@@ -797,7 +1213,6 @@ tramite il contenuto della struttura \struct{siginfo\_t}.
   \label{tab:file_notify}
 \end{table}
 
-
 Ci si può registrare per le notifiche dei cambiamenti al contenuto di una
 certa directory eseguendo la funzione \func{fcntl} su un file descriptor
 associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso
@@ -819,20 +1234,36 @@ specificare un valore nullo.
 
 \index{file!inotify|(}
 
-Il maggiore problema di \textit{dnotify} è quello della scalabilità, e della
-complessità di gestione dovuta all'uso dei segnali. Per questo motivo a
-partire dal kernel 2.6.13 è stata introdotta una nuova interfaccia per
-l'osservazione delle modifiche a file o directory, chiamata
-\textit{inotify}.\footnote{le corrispondenti funzioni di interfaccia sono
-  state introdotte nelle glibc 2.4.}
+Il maggiore problema di \textit{dnotify} è quello della scalabilità: si deve
+usare un file descriptor per ciascuna directory che si vuole tenere sotto
+controllo, il che porta facilmente ad avere un eccesso di file aperti. Inoltre
+quando la directory che si controlla è all'interno di un dispositivo
+rimovibile, mantenere il relativo file descriptor aperto comporta
+l'impossibilità di smontare il dispositivo e di rimuoverlo, il che in genere
+complica notevolmente la gestione dell'uso di questi dispositivi.
+
+Un altro problema è che l'interfaccia di \textit{dnotify} consente solo di
+tenere sotto controllo il contenuto di una directory; la modifica di un file
+viene segnalata, ma poi è necessario verificare di quale file si tratta
+(operazione che può essere molto onerosa quando una directory contiene un gran
+numero di file).  Infine l'uso dei segnali come interfaccia di notifica
+comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e
+sez.~\ref{sec:sig_adv_control}.  Per tutta questa serie di motivi in generale
+quella di \textit{dnotify} viene considerata una interfaccia di usabilità
+problematica.
 
 \index{file!dnotify|)}
 
-L'interfaccia di \textit{inotify} è una caratteristica specifica di Linux
-(pertanto non deve essere usata se si devono scrivere programmi portabili), ed
-è basata sull'uso di una coda di notifica degli eventi associata ad un file
-descriptor. La coda viene creata attraverso la funzione \funcd{inotify\_init},
-il cui prototipo è:
+Per risolvere i problemi appena illustrati è stata introdotta una nuova
+interfaccia per l'osservazione delle modifiche a file o directory, chiamata
+\textit{inotify}.\footnote{l'interfaccia è disponibile a partire dal kernel
+  2.6.13, le relative funzioni sono state introdotte nelle glibc 2.4.}  Anche
+questa è una interfaccia specifica di Linux (pertanto non deve essere usata se
+si devono scrivere programmi portabili), ed è basata sull'uso di una coda di
+notifica degli eventi associata ad un singolo file descriptor, il che permette
+di risolvere il principale problema di \itindex{dnotify} \textit{dnotify}.  La
+coda viene creata attraverso la funzione \funcd{inotify\_init}, il cui
+prototipo è:
 \begin{prototype}{sys/inotify.h}
   {int inotify\_init(void)}
   
@@ -851,99 +1282,206 @@ il cui prototipo 
 }
 \end{prototype}
 
-La funzione non prende alcun argomento, e restituisce un file descriptor
-associato alla coda, attraverso il quale verranno effettuate le operazioni di
-notifica. Si tratta di un file descriptor speciale, che non è associato a
-nessun file, ma che viene utilizzato per notificare gli eventi che si sono
-posti in osservazione all'applicazione che usa l'interfaccia di
-\textit{inotify}. 
-
-Trattandosi di file descriptor a tutti gli effetti, esso potrà essere
-utilizzato con le funzioni \func{select} e \func{poll}. Dato che gli eventi
-vengono notificati come dati disponibili in lettura sul file descriptor
-stesso, dette funzioni ritorneranno tutte le volte che si avrà un evento di
-notifica. Si potrà cioè gestirlo secondo le modalità illustrate in
-sez.~\ref{sec:file_multiplexing}. Inoltre, come per i file descriptor
-associati ai socket (vedi sez.~\ref{sec:sock_ioctl_IP}) si potrà ottenere il
-numero di byte disponibili in lettura eseguendo su di esso l'operazione
-\const{FIONREAD} con \func{ioctl}.
-
-Una volta creata la coda di notifica, ed ottenuto il relativo file descriptor,
-l'interfaccia prevede che si definiscano gli eventi da tenere sotto
-osservazione associando ad esso una \textsl{lista di osservazione} (o
-\textit{watch list}) che indica quali file e directory tenere d'occhio. Per
-gestire la lista di osservazione l'interfaccia fornisce due funzioni, la prima
-di queste è \funcd{inotify\_add\_watch}, il cui prototipo è:
+La funzione non prende alcun argomento; inizializza una istanza di
+\textit{inotify} e restituisce un file descriptor attraverso il quale verranno
+effettuate le operazioni di notifica;\footnote{per evitare abusi delle risorse
+  di sistema è previsto che un utente possa utilizzare un numero limitato di
+  istanze di \textit{inotify}; il valore di default del limite è di 128, ma
+  questo valore può essere cambiato con \func{sysctl} o usando il file
+  \procfile{/proc/sys/fs/inotify/max\_user\_instances}.} si tratta di un file
+descriptor speciale che non è associato a nessun file su disco, e che viene
+utilizzato solo per notificare gli eventi che sono stati posti in
+osservazione. Dato che questo file descriptor non è associato a nessun file o
+directory reale, l'inconveniente di non poter smontare un filesystem i cui
+file sono tenuti sotto osservazione viene completamente
+eliminato.\footnote{anzi, una delle capacità dell'interfaccia di
+  \textit{inotify} è proprio quella di notificare il fatto che il filesystem
+  su cui si trova il file o la directory osservata è stato smontato.}
+
+Inoltre trattandosi di un file descriptor a tutti gli effetti, esso potrà
+essere utilizzato come argomento per le funzioni \func{select} e \func{poll} e
+con l'interfaccia di \textit{epoll}; siccome gli eventi vengono notificati
+come dati disponibili in lettura, dette funzioni ritorneranno tutte le volte
+che si avrà un evento di notifica. Così, invece di dover utilizzare i
+segnali,\footnote{considerati una pessima scelta dal punto di vista
+  dell'interfaccia utente.} si potrà gestire l'osservazione degli eventi con
+una qualunque delle modalità di \textit{I/O multiplexing} illustrate in
+sez.~\ref{sec:file_multiplexing}. Qualora si voglia cessare l'osservazione,
+sarà sufficiente chiudere il file descriptor e tutte le risorse allocate
+saranno automaticamente rilasciate.
+
+Infine l'interfaccia di \textit{inotify} consente di mettere sotto
+osservazione, oltre che una directory, anche singoli file.  Una volta creata
+la coda di notifica si devono definire gli eventi da tenere sotto
+osservazione; questo viene fatto attraverso una \textsl{lista di osservazione}
+(o \textit{watch list}) che è associata alla coda. Per gestire la lista di
+osservazione l'interfaccia fornisce due funzioni, la prima di queste è
+\funcd{inotify\_add\_watch}, il cui prototipo è:
 \begin{prototype}{sys/inotify.h}
   {int inotify\_add\_watch(int fd, const char *pathname, uint32\_t mask)}
 
   Aggiunge un evento di osservazione alla lista di osservazione di \param{fd}.
-  
+
   \bodydesc{La funzione restituisce un valore positivo in caso di successo, o
     $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
   \item[\errcode{EACCESS}] non si ha accesso in lettura al file indicato.
   \item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
-    non è un filesystem di \textit{inotify}.
+    non è un file descriptor di \textit{inotify}.
   \item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
     osservazione o il kernel non ha potuto allocare una risorsa necessaria.
   \end{errlist}
   ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF}.}
 \end{prototype}
 
-La funzione consente di creare un \textsl{evento di osservazione} (un
-cosiddetto ``\textit{watch}'') nella lista di osservazione di una coda di
-notifica. Quest'ultima viene identificata specificando il file descriptor ad
-essa associato nell'argomento \param{fd}. Il file da porre sotto osservazione
-viene invece identificato tramite il suo pathname passato nell'argomento
-\param{pathname}, infine il terzo argomento, \param{mask}, è una maschera
-binaria che consente di specificare quali tipologie di eventi accaduti sul
-file devono essere osservati, e deve essere specificato con una OR aritmetico
-delle costanti riportate in tab.~\ref{tab:inotify_event_watch}.
-
+La funzione consente di creare un ``\textsl{osservatore}'' (il cosiddetto
+``\textit{watch}'') nella lista di osservazione di una coda di notifica, che
+deve essere indicata specificando il file descriptor ad essa associato
+nell'argomento \param{fd}.\footnote{questo ovviamente dovrà essere un file
+  descriptor creato con \func{inotify\_init}.}  Il file o la directory da
+porre sotto osservazione vengono invece indicati per nome, da passare
+nell'argomento \param{pathname}.  Infine il terzo argomento, \param{mask},
+indica che tipo di eventi devono essere tenuti sotto osservazione e le
+modalità della stessa.  L'operazione può essere ripetuta per tutti i file e le
+directory che si vogliono tenere sotto osservazione,\footnote{anche in questo
+  caso c'è un limite massimo che di default è pari a 8192, ed anche questo
+  valore può essere cambiato con \func{sysctl} o usando il file
+  \procfile{/proc/sys/fs/inotify/max\_user\_watches}.} e si utilizzerà sempre
+un solo file descriptor.
+
+Il tipo di evento che si vuole osservare deve essere specificato
+nell'argomento \param{mask} come maschera binaria, combinando i valori delle
+costanti riportate in tab.~\ref{tab:inotify_event_watch} che identificano i
+singoli bit della maschera ed il relativo significato. In essa si sono marcati
+con un ``$\bullet$'' gli eventi che, quando specificati per una directory,
+vengono osservati anche su tutti i file che essa contiene.  Nella seconda
+parte della tabella si sono poi indicate alcune combinazioni predefinite dei
+flag della prima parte.
 
 \begin{table}[htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|l|p{8cm}|}
+  \begin{tabular}[c]{|l|c|p{10cm}|}
     \hline
-    \textbf{Valore}  & \textbf{Significato} \\
+    \textbf{Valore}  & \textbf{Significato} \\
     \hline
     \hline
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
-    \const{}& .\\ 
+    \const{IN\_ACCESS}        &$\bullet$& C'è stato accesso al file in
+                                          lettura.\\  
+    \const{IN\_ATTRIB}        &$\bullet$& Ci sono stati cambiamenti sui dati
+                                          dell'inode (o sugli attributi
+                                          estesi, vedi
+                                          sez.~\ref{sec:file_xattr}).\\ 
+    \const{IN\_CLOSE\_WRITE}  &$\bullet$& È stato chiuso un file aperto in
+                                          scrittura.\\  
+    \const{IN\_CLOSE\_NOWRITE}&$\bullet$& È stato chiuso un file aperto in
+                                          sola lettura.\\
+    \const{IN\_CREATE}        &$\bullet$& È stato creato un file o una
+                                          directory in una directory sotto
+                                          osservazione.\\  
+    \const{IN\_DELETE}        &$\bullet$& È stato cancellato un file o una
+                                          directory in una directory sotto
+                                          osservazione.\\ 
+    \const{IN\_DELETE\_SELF}  & --      & È stato cancellato il file (o la
+                                          directory) sotto osservazione.\\ 
+    \const{IN\_MODIFY}        &$\bullet$& È stato modificato il file.\\ 
+    \const{IN\_MOVE\_SELF}    &         & È stato rinominato il file (o la
+                                          directory) sotto osservazione.\\ 
+    \const{IN\_MOVED\_FROM}   &$\bullet$& Un file è stato spostato fuori dalla
+                                          directory sotto osservazione.\\ 
+    \const{IN\_MOVED\_TO}     &$\bullet$& Un file è stato spostato nella
+                                          directory sotto osservazione.\\ 
+    \const{IN\_OPEN}          &$\bullet$& Un file è stato aperto.\\ 
+    \hline    
+    \const{IN\_CLOSE}         &         & Combinazione di
+                                          \const{IN\_CLOSE\_WRITE} e
+                                          \const{IN\_CLOSE\_NOWRITE}.\\  
+    \const{IN\_MOVE}          &         & Combinazione di
+                                          \const{IN\_MOVED\_FROM} e
+                                          \const{IN\_MOVED\_TO}.\\
+    \const{IN\_ALL\_EVENTS}   &         & Combinazione di tutti i flag
+                                          possibili.\\
     \hline    
   \end{tabular}
-  \caption{Le costanti che identificano i valori per la maschera binaria
-    dell'argomento \param{mask} di \func{inotify\_add\_watch}.} 
+  \caption{Le costanti che identificano i bit della maschera binaria
+    dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano il
+    tipo di evento da tenere sotto osservazione.} 
   \label{tab:inotify_event_watch}
 \end{table}
 
+Oltre ai flag di tab.~\ref{tab:inotify_event_watch}, che indicano il tipo di
+evento da osservare e che vengono utilizzati anche in uscita per indicare il
+tipo di evento avvenuto, \func{inotify\_add\_watch} supporta ulteriori
+flag,\footnote{i flag \const{IN\_DONT\_FOLLOW}, \const{IN\_MASK\_ADD} e
+  \const{IN\_ONLYDIR} sono stati introdotti a partire dalle glibc 2.5, se si
+  usa la versione 2.4 è necessario definirli a mano.}  riportati in
+tab.~\ref{tab:inotify_add_watch_flag}, che indicano le modalità di
+osservazione (da passare sempre nell'argomento \param{mask}) e che al
+contrario dei precedenti non vengono mai impostati nei risultati in uscita.
 
-Dato che può esistere un solo \textit{watch} per file, qualora venga
-specificato il pathname di un file che era già stato posto in osservazione, la
-funzione sovrascriverà le impostazioni precedenti. In caso di successo la
-funzione ritorna un intero positivo, detto \textit{watch descriptor} che
-identifica univocamente l'evento di osservazione. Questo valore è importante
-perché è soltanto con esso che si può rimuovere un evento di osservazione,
-usando la seconda funzione dell'interfaccia di gestione,
-\funcd{inotify\_rm\_watch}, il cui prototito è:
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{IN\_DONT\_FOLLOW}& Non dereferenzia \param{pathname} se questo è un
+                              link simbolico.\\
+    \const{IN\_MASK\_ADD}   & Aggiunge a quelli già impostati i flag indicati
+                              nell'argomento \param{mask}, invece di
+                              sovrascriverli.\\
+    \const{IN\_ONESHOT}     & Esegue l'osservazione su \param{pathname} per una
+                              sola volta, rimuovendolo poi dalla \textit{watch
+                                list}.\\ 
+    \const{IN\_ONLYDIR}     & Se \param{pathname} è una directory riporta
+                              soltanto gli eventi ad essa relativi e non
+                              quelli per i file che contiene.\\ 
+    \hline    
+  \end{tabular}
+  \caption{Le costanti che identificano i bit della maschera binaria
+    dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano le
+    modalità di osservazione.} 
+  \label{tab:inotify_add_watch_flag}
+\end{table}
+
+Se non esiste nessun \textit{watch} per il file o la directory specificata
+questo verrà creato per gli eventi specificati dall'argomento \param{mask},
+altrimenti la funzione sovrascriverà le impostazioni precedenti, a meno che
+non si sia usato il flag \const{IN\_MASK\_ADD}, nel qual caso gli eventi
+specificati saranno aggiunti a quelli già presenti.
+
+Come accennato quando si tiene sotto osservazione una directory vengono
+restituite le informazioni sia riguardo alla directory stessa che ai file che
+essa contiene; questo comportamento può essere disabilitato utilizzando il
+flag \const{IN\_ONLYDIR}, che richiede di riportare soltanto gli eventi
+relativi alla directory stessa. Si tenga presente inoltre che quando si
+osserva una directory vengono riportati solo gli eventi sui file che essa
+contiene direttamente, non quelli relativi a file contenuti in eventuali
+sottodirectory; se si vogliono osservare anche questi sarà necessario creare
+ulteriori \textit{watch} per ciascuna sottodirectory.
+
+Infine usando il flag \const{IN\_ONESHOT} è possibile richiedere una notifica
+singola;\footnote{questa funzionalità però è disponibile soltanto a partire dal
+  kernel 2.6.16.} una volta verificatosi uno qualunque fra gli eventi
+richiesti con \func{inotify\_add\_watch} l'\textsl{osservatore} verrà
+automaticamente rimosso dalla lista di osservazione e nessun ulteriore evento
+sarà più notificato.
+
+In caso di successo \func{inotify\_add\_watch} ritorna un intero positivo,
+detto \textit{watch descriptor}, che identifica univocamente un
+\textsl{osservatore} su una coda di notifica; esso viene usato per farvi
+riferimento sia riguardo i risultati restituiti da \textit{inotify}, che per
+la eventuale rimozione dello stesso. 
+
+La seconda funzione per la gestione delle code di notifica, che permette di
+rimuovere un \textsl{osservatore}, è \funcd{inotify\_rm\_watch}, ed il suo
+prototipo è:
 \begin{prototype}{sys/inotify.h}
   {int inotify\_rm\_watch(int fd, uint32\_t wd)}
 
-  Rimuove un evento di osservazione.
+  Rimuove un \textsl{osservatore} da una coda di notifica.
   
   \bodydesc{La funzione restituisce 0 in caso di successo, o $-1$ in caso di
     errore, nel qual caso \var{errno} assumerà uno dei valori:
@@ -956,18 +1494,244 @@ usando la seconda funzione dell'interfaccia di gestione,
 }
 \end{prototype}
 
+La funzione rimuove dalla coda di notifica identificata dall'argomento
+\param{fd} l'osservatore identificato dal \textit{watch descriptor}
+\param{wd};\footnote{ovviamente deve essere usato per questo argomento un
+  valore ritornato da \func{inotify\_add\_watch}, altrimenti si avrà un errore
+  di \errval{EINVAL}.} in caso di successo della rimozione, contemporaneamente
+alla cancellazione dell'osservatore, sulla coda di notifica verrà generato un
+evento di tipo \const{IN\_IGNORED} (vedi
+tab.~\ref{tab:inotify_read_event_flag}). Si tenga presente che se un file
+viene cancellato o un filesystem viene smontato i relativi osservatori vengono
+rimossi automaticamente e non è necessario utilizzare
+\func{inotify\_rm\_watch}.
+
+Come accennato l'interfaccia di \textit{inotify} prevede che gli eventi siano
+notificati come dati presenti in lettura sul file descriptor associato alla
+coda di notifica. Una applicazione pertanto dovrà leggere i dati da detto file
+con una \func{read}, che ritornerà sul buffer i dati presenti nella forma di
+una o più strutture di tipo \struct{inotify\_event} (la cui definizione è
+riportata in fig.~\ref{fig:inotify_event}). Qualora non siano presenti dati la
+\func{read} si bloccherà (a meno di non aver impostato il file descriptor in
+modalità non bloccante) fino all'arrivo di almeno un evento.
 
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/inotify_event.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{inotify\_event} usata dall'interfaccia di
+    \textit{inotify} per riportare gli eventi.}
+  \label{fig:inotify_event}
+\end{figure}
 
+Una ulteriore caratteristica dell'interfaccia di \textit{inotify} è che essa
+permette di ottenere con \func{ioctl}, come per i file descriptor associati ai
+socket (si veda sez.~\ref{sec:sock_ioctl_IP}) il numero di byte disponibili in
+lettura sul file descriptor, utilizzando su di esso l'operazione
+\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
+  (vedi sez.~\ref{sec:file_ioctl}), che è disponibile solo per i socket e per
+  i file descriptor creati con \func{inotify\_init}.} Si può così utilizzare
+questa operazione, oltre che per predisporre una operazione di lettura con un
+buffer di dimensioni adeguate, anche per ottenere rapidamente il numero di
+file che sono cambiati.
+
+Una volta effettuata la lettura con \func{read} a ciascun evento sarà
+associata una struttura \struct{inotify\_event} contenente i rispettivi dati.
+Per identificare a quale file o directory l'evento corrisponde viene
+restituito nel campo \var{wd} il \textit{watch descriptor} con cui il relativo
+osservatore è stato registrato. Il campo \var{mask} contiene invece una
+maschera di bit che identifica il tipo di evento verificatosi; in essa
+compariranno sia i bit elencati nella prima parte di
+tab.~\ref{tab:inotify_event_watch}, che gli eventuali valori
+aggiuntivi\footnote{questi compaiono solo nel campo \var{mask} di
+  \struct{inotify\_event}, e  non utilizzabili in fase di registrazione
+  dell'osservatore.} di tab.~\ref{tab:inotify_read_event_flag}.
 
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{IN\_IGNORED}    & L'osservatore è stato rimosso, sia in maniera 
+                             esplicita con l'uso di \func{inotify\_rm\_watch}, 
+                             che in maniera implicita per la rimozione 
+                             dell'oggetto osservato o per lo smontaggio del
+                             filesystem su cui questo si trova.\\
+    \const{IN\_ISDIR}      & L'evento avvenuto fa riferimento ad una directory
+                             (consente così di distinguere, quando si pone
+                             sotto osservazione una directory, fra gli eventi
+                             relativi ad essa e quelli relativi ai file che
+                             essa contiene).\\
+    \const{IN\_Q\_OVERFLOW}& Si sono eccedute le dimensioni della coda degli
+                             eventi (\textit{overflow} della coda); in questo
+                             caso il valore di \var{wd} è $-1$.\footnotemark\\
+    \const{IN\_UNMOUNT}    & Il filesystem contenente l'oggetto posto sotto
+                             osservazione è stato smontato.\\
+    \hline    
+  \end{tabular}
+  \caption{Le costanti che identificano i bit aggiuntivi usati nella maschera
+    binaria del campo \var{mask} di \struct{inotify\_event}.} 
+  \label{tab:inotify_read_event_flag}
+\end{table}
 
-% TODO inserire anche inotify, vedi http://www.linuxjournal.com/article/8478
-% TODO e man inotify
-
-\index{file!inotify|)}
-
+\footnotetext{la coda di notifica ha una dimensione massima specificata dal
+  parametro di sistema \procfile{/proc/sys/fs/inotify/max\_queued\_events} che
+  indica il numero massimo di eventi che possono essere mantenuti sulla
+  stessa; quando detto valore viene ecceduto gli ulteriori eventi vengono
+  scartati, ma viene comunque generato un evento di tipo
+  \const{IN\_Q\_OVERFLOW}.}
+
+Il campo \var{cookie} contiene invece un intero univoco che permette di
+identificare eventi correlati (per i quali avrà lo stesso valore), al momento
+viene utilizzato soltanto per rilevare lo spostamento di un file, consentendo
+così all'applicazione di collegare la corrispondente coppia di eventi
+\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
+
+Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
+l'evento è relativo ad un file presente in una directory posta sotto
+osservazione, in tal caso essi contengono rispettivamente il nome del file
+(come pathname relativo alla directory osservata) e la relativa dimensione in
+byte. Il campo \var{name} viene sempre restituito come stringa terminata da
+NUL, con uno o più zeri di terminazione, a seconda di eventuali necessità di
+allineamento del risultato, ed il valore di \var{len} corrisponde al totale
+della dimensione di \var{name}, zeri aggiuntivi compresi. La stringa con il
+nome del file viene restituita nella lettura subito dopo la struttura
+\struct{inotify\_event}; questo significa che le dimensioni di ciascun evento
+di \textit{inotify} saranno pari a \code{sizeof(\struct{inotify\_event}) +
+  len}.
+
+Vediamo allora un esempio dell'uso dell'interfaccia di \textit{inotify} con un
+semplice programma che permette di mettere sotto osservazione uno o più file e
+directory. Il programma si chiama \texttt{inotify\_monitor.c} ed il codice
+completo è disponibile coi sorgenti allegati alla guida, il corpo principale
+del programma, che non contiene la sezione di gestione delle opzioni e le
+funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}.
+
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/inotify_monitor.c}
+  \end{minipage}
+  \normalsize
+  \caption{Esempio di codice che usa l'interfaccia di \textit{inotify}.}
+  \label{fig:inotify_monitor_example}
+\end{figure}
 
+Una volta completata la scansione delle opzioni il corpo principale del
+programma inizia controllando (\texttt{\small 11--15}) che sia rimasto almeno
+un argomento che indichi quale file o directory mettere sotto osservazione (e
+qualora questo non avvenga esce stampando la pagina di aiuto); dopo di che
+passa (\texttt{\small 16--20}) all'inizializzazione di \textit{inotify}
+ottenendo con \func{inotify\_init} il relativo file descriptor (oppure usce in
+caso di errore).
+
+Il passo successivo è aggiungere (\texttt{\small 21--30}) alla coda di
+notifica gli opportuni osservatori per ciascuno dei file o directory indicati
+all'invocazione del comando; questo viene fatto eseguendo un ciclo
+(\texttt{\small 22--29}) fintanto che la variabile \var{i}, inizializzata a
+zero (\texttt{\small 21}) all'inizio del ciclo, è minore del numero totale di
+argomenti rimasti. All'interno del ciclo si invoca (\texttt{\small 23})
+\func{inotify\_add\_watch} per ciascuno degli argomenti, usando la maschera
+degli eventi data dalla variabile \var{mask} (il cui valore viene impostato
+nella scansione delle opzioni), in caso di errore si esce dal programma
+altrimenti si incrementa l'indice (\texttt{\small 29}).
+
+Completa l'inizializzazione di \textit{inotify} inizia il ciclo principale
+(\texttt{\small 32--56}) del programma, nel quale si resta in attesa degli
+eventi che si intendono osservare. Questo viene fatto eseguendo all'inizio del
+ciclo (\texttt{\small 33}) una \func{read} che si bloccherà fintanto che non
+si saranno verificati eventi. 
+
+Dato che l'interfaccia di \textit{inotify} può riportare anche più eventi in
+una sola lettura, si è avuto cura di passare alla \func{read} un buffer di
+dimensioni adeguate, inizializzato in (\texttt{\small 7}) ad un valore di
+approssimativamente 512 eventi.\footnote{si ricordi che la quantità di dati
+  restituita da \textit{inotify} è variabile a causa della diversa lunghezza
+  del nome del file restituito insieme a \struct{inotify\_event}.} In caso di
+errore di lettura (\texttt{\small 35--40}) il programma esce con un messaggio
+di errore (\texttt{\small 37--39}), a meno che non si tratti di una
+interruzione della system call, nel qual caso (\texttt{\small 36}) si ripete la
+lettura.
+
+Se la lettura è andata a buon fine invece si esegue un ciclo (\texttt{\small
+  43--52}) per leggere tutti gli eventi restituiti, al solito si inizializza
+l'indice \var{i} a zero (\texttt{\small 42}) e si ripetono le operazioni
+(\texttt{\small 43}) fintanto che esso non supera il numero di byte restituiti
+in lettura. Per ciascun evento all'interno del ciclo si assegna\footnote{si
+  noti come si sia eseguito un opportuno \textit{casting} del puntatore.} alla
+variabile \var{event} l'indirizzo nel buffer della corrispondente struttura
+\struct{inotify\_event} (\texttt{\small 44}), e poi si stampano il numero di
+\textit{watch descriptor} (\texttt{\small 45}) ed il file a cui questo fa
+riferimento (\texttt{\small 46}), ricavato dagli argomenti passati a riga di
+comando sfruttando il fatto che i \textit{watch descriptor} vengono assegnati
+in ordine progressivo crescente a partire da 1.
+
+Qualora sia presente il riferimento ad un nome di file associato all'evento lo
+si stampa (\texttt{\small 47--49}); si noti come in questo caso si sia
+utilizzato il valore del campo \var{event->len} e non al fatto che
+\var{event->name} riporti o meno un puntatore nullo.\footnote{l'interfaccia
+  infatti, qualora il nome non sia presente, non avvalora il campo
+  \var{event->name}, che si troverà a contenere quello che era precedentemente
+  presente nella rispettiva locazione di memoria, nel caso più comune il
+  puntatore al nome di un file osservato in precedenza.} Si utilizza poi
+(\texttt{\small 50}) la funzione \code{printevent}, che interpreta il valore
+del campo \var{event->mask} per stampare il tipo di eventi
+accaduti.\footnote{per il relativo codice, che non riportiamo in quanto non
+  essenziale alla comprensione dell'esempio, si possono utilizzare direttamente
+  i sorgenti allegati alla guida.} Infine (\texttt{\small 51}) si provvede ad
+aggiornare l'indice \var{i} per farlo puntare all'evento successivo.
+
+Se adesso usiamo il programma per mettere sotto osservazione una directory, e
+da un altro terminale eseguiamo il comando \texttt{ls} otterremo qualcosa del
+tipo di:
+\begin{verbatim}
+piccardi@gethen:~/gapil/sources$ ./inotify_monitor -a /home/piccardi/gapil/
+Watch descriptor 1
+Observed event on /home/piccardi/gapil/
+IN_OPEN, 
+Watch descriptor 1
+Observed event on /home/piccardi/gapil/
+IN_CLOSE_NOWRITE, 
+\end{verbatim}
 
+I lettori più accorti si saranno resi conto che nel ciclo di lettura degli
+eventi appena illustrato non viene trattato il caso particolare in cui la
+funzione \func{read} restituisce in \var{nread} un valore nullo. Lo si è fatto
+perché con \textit{inotify} il ritorno di una \func{read} con un valore nullo
+avviene soltanto, come forma di avviso, quando si sia eseguita la funzione
+specificando un buffer di dimensione insufficiente a contenere anche un solo
+evento. Nel nostro caso le dimensioni erano senz'altro sufficienti, per cui
+tale evenienza non si verificherà mai.
+
+Ci si potrà però chiedere cosa succede se il buffer è sufficiente per un
+evento, ma non per tutti gli eventi verificatisi. Come si potrà notare nel
+codice illustrato in precedenza non si è presa nessuna precauzione per
+verificare che non ci fossero stati troncamenti dei dati. Anche in questo caso
+il comportamento scelto è corretto, perché l'interfaccia di \textit{inotify}
+garantisce automaticamente, anche quando ne sono presenti in numero maggiore,
+di restituire soltanto il numero di eventi che possono rientrare completamente
+nelle dimensioni del buffer specificato.\footnote{si avrà cioè, facendo
+  riferimento sempre al codice di fig.~\ref{fig:inotify_monitor_example}, che
+  \var{read} sarà in genere minore delle dimensioni di \var{buffer} ed uguale
+  soltanto qualora gli eventi corrispondano esattamente alle dimensioni di
+  quest'ultimo.} Se gli eventi sono di più saranno restituiti solo quelli che
+entrano interamente nel buffer e gli altri saranno restituiti alla successiva
+chiamata di \func{read}.
+
+Infine un'ultima caratteristica dell'interfaccia di \textit{inotify} è che gli
+eventi restituiti nella lettura formano una sequenza ordinata, è cioè
+garantito che se si esegue uno spostamento di un file gli eventi vengano
+generati nella sequenza corretta. L'interfaccia garantisce anche che se si
+verificano più eventi consecutivi identici (vale a dire con gli stessi valori
+dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono
+raggruppati in un solo evento.
 
+\index{file!inotify|)}
 
 
 \subsection{L'interfaccia POSIX per l'I/O asincrono}
@@ -1090,11 +1854,11 @@ appena descritta; i rispettivi prototipi sono:
   \bodydesc{Le funzioni restituiscono 0 in caso di successo, 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.
-  \item[\errcode{ENOSYS}] La funzione non è implementata.
-  \item[\errcode{EINVAL}] Si è specificato un valore non valido per i campi
+  \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
+  \item[\errcode{ENOSYS}] la funzione non è implementata.
+  \item[\errcode{EINVAL}] si è specificato un valore non valido per i campi
     \var{aio\_offset} o \var{aio\_reqprio} di \param{aiocbp}.
-  \item[\errcode{EAGAIN}] La coda delle richieste è momentaneamente piena.
+  \item[\errcode{EAGAIN}] la coda delle richieste è momentaneamente piena.
   \end{errlist}
 }
 \end{functions}
@@ -1205,7 +1969,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, \funcd{aio\_cancel}, che
+standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
 permette di cancellare una operazione richiesta in precedenza; il suo
 prototipo è:
 \begin{prototype}{aio.h}
@@ -1261,10 +2025,10 @@ specifica operazione; il suo prototipo 
     completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
     dei valori:
     \begin{errlist}
-    \item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro
+    \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
       \param{timeout}.
-    \item[\errcode{ENOSYS}] La funzione non è implementata.
-    \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale.
+    \item[\errcode{ENOSYS}] la funzione non è implementata.
+    \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
     \end{errlist}
   }
 \end{prototype}
@@ -1292,13 +2056,13 @@ lettura o scrittura; il suo prototipo 
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore, nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EAGAIN}] Nessuna operazione è stata completata entro
+    \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
       \param{timeout}.
-    \item[\errcode{EINVAL}] Si è passato un valore di \param{mode} non valido
+    \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.
+    \item[\errcode{ENOSYS}] la funzione non è implementata.
+    \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
     \end{errlist}
   }
 \end{prototype}
@@ -1334,79 +2098,8 @@ Oltre alle precedenti modalit
   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 sez.~\ref{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} e la funzione
-\func{sendfile}.
-
-
-\subsection{I/O vettorizzato}
-\label{sec:file_multiple_io}
-
-Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
-serie multipla di operazioni di I/O, come una serie di letture o scritture di
-vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
-una struttura ed essi devono essere caricati o salvati su un file.  Benché
-l'operazione sia facilmente eseguibile attraverso una serie multipla di
-chiamate, ci sono casi in cui si vuole poter contare sulla atomicità delle
-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
-  \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, \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:
-\begin{functions}
-  \headdecl{sys/uio.h}
-  
-  \funcdecl{int readv(int fd, const struct iovec *vector, int count)} 
-  \funcdecl{int writev(int fd, const struct iovec *vector, int count)} 
-
-  Eseguono rispettivamente una lettura o una scrittura vettorizzata.
-  
-  \bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
-    caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
-    assumerà uno dei valori:
-  \begin{errlist}
-  \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
-    argomenti (ad esempio \param{count} è maggiore di \const{MAX\_IOVEC}).
-  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
-    di avere eseguito una qualunque lettura o scrittura.
-  \item[\errcode{EAGAIN}] \param{fd} è stato aperto in modalità non bloccante e
-  non ci sono dati in lettura.
-  \item[\errcode{EOPNOTSUPP}] la coda delle richieste è momentaneamente piena.
-  \end{errlist}
-  ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
-  (se non sono stati allocati correttamente i buffer specificati nei campi
-  \var{iov\_base}), più gli eventuali errori delle funzioni di lettura e
-  scrittura eseguite su \param{fd}.}
-\end{functions}
-
-Entrambe le funzioni usano una struttura \struct{iovec}, la cui definizione è
-riportata in fig.~\ref{fig:file_iovec}, che definisce dove i dati devono
-essere letti o scritti ed in che quantità. Il primo campo della struttura,
-\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
-\var{iov\_len}, la dimensione dello stesso.
-
-\begin{figure}[!htb]
-  \footnotesize \centering
-  \begin{minipage}[c]{15cm}
-    \includestruct{listati/iovec.h}
-  \end{minipage} 
-  \normalsize 
-  \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
-    vettorizzato.} 
-  \label{fig:file_iovec}
-\end{figure}
-
-La lista dei buffer da utilizzare viene indicata attraverso l'argomento
-\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
-è specificata dall'argomento \param{count}.  Ciascuna struttura dovrà essere
-inizializzata opportunamente per indicare i vari buffer da e verso i quali
-verrà eseguito il trasferimento dei dati. Essi verranno letti (o scritti)
-nell'ordine in cui li si sono specificati nel vettore \param{vector}.
+sezione allora prenderemo in esame le interfacce per l'\textsl{I/O mappato in
+  memoria}, per l'\textsl{I/O vettorizzato} e altre funzioni di I/O avanzato.
 
 
 \subsection{File mappati in memoria}
@@ -1422,7 +2115,7 @@ file in una sezione dello spazio di indirizzi del processo.
  che lo ha allocato
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=10cm]{img/mmap_layout}
+  \includegraphics[width=12cm]{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}
@@ -1479,29 +2172,29 @@ eseguire la mappatura in memoria di un file, 
     in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
     qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EBADF}] Il file descriptor non è valido, e non si è usato
+    \item[\errcode{EBADF}] il file descriptor non è valido, e non si è usato
       \const{MAP\_ANONYMOUS}.
     \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
+    \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).
-    \item[\errcode{ETXTBSY}] Si è impostato \const{MAP\_DENYWRITE} ma
+    \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma
       \param{fd} è aperto in scrittura.
-    \item[\errcode{EAGAIN}] Il file è bloccato, o si è bloccata troppa memoria
+    \item[\errcode{EAGAIN}] il file è bloccato, o si è bloccata troppa memoria
       rispetto a quanto consentito dai limiti di sistema (vedi
       sez.~\ref{sec:sys_resource_limit}).
-    \item[\errcode{ENOMEM}] Non c'è memoria o si è superato il limite sul
+    \item[\errcode{ENOMEM}] non c'è memoria o si è superato il limite sul
       numero di mappature possibili.
-    \item[\errcode{ENODEV}] Il filesystem di \param{fd} non supporta il memory
+    \item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory
       mapping.
-    \item[\errcode{EPERM}] L'argomento \param{prot} ha richiesto
+    \item[\errcode{EPERM}] l'argomento \param{prot} ha richiesto
       \const{PROT\_EXEC}, ma il filesystem di \param{fd} è montato con
       l'opzione \texttt{noexec}.
-    \item[\errcode{ENFILE}] Si è superato il limite del sistema sul numero di
+    \item[\errcode{ENFILE}] si è superato il limite del sistema sul numero di
       file aperti (vedi sez.~\ref{sec:sys_resource_limit}).
     \end{errlist}
   }
@@ -1532,7 +2225,6 @@ multiplo della dimensione di una pagina di memoria.
   \label{tab:file_mmap_prot}
 \end{table}
 
-
 Il valore dell'argomento \param{prot} indica la protezione\footnote{in Linux
   la memoria reale è divisa in pagine: ogni processo vede la sua memoria
   attraverso uno o più segmenti lineari di memoria virtuale.  Per ciascuno di
@@ -1542,7 +2234,7 @@ Il valore dell'argomento \param{prot} indica la protezione\footnote{in Linux
   che si chiama una \textit{segment violation}, e la relativa emissione del
   segnale \const{SIGSEGV}.} da applicare al segmento di memoria e deve essere
 specificato come maschera binaria ottenuta dall'OR di uno o più dei valori
-riportati in tab.~\ref{tab:file_mmap_flag}; il valore specificato deve essere
+riportati in tab.~\ref{tab:file_mmap_prot}; il valore specificato deve essere
 compatibile con la modalità di accesso con cui si è aperto il file.
 
 L'argomento \param{flags} specifica infine qual è il tipo di oggetto mappato,
@@ -1564,7 +2256,7 @@ tab.~\ref{tab:file_mmap_flag}.
                              da \param{start}, se questo non può essere usato
                              \func{mmap} fallisce. Se si imposta questo flag il
                              valore di \param{start} deve essere allineato
-                             alle dimensioni di una pagina. \\
+                             alle dimensioni di una pagina.\\
     \const{MAP\_SHARED}    & I cambiamenti sulla memoria mappata vengono
                              riportati sul file e saranno immediatamente
                              visibili agli altri processi che mappano lo stesso
@@ -1572,7 +2264,7 @@ tab.~\ref{tab:file_mmap_flag}.
                              aggiornato fino alla chiamata di \func{msync} o
                              \func{munmap}), e solo allora le modifiche saranno
                              visibili per l'I/O convenzionale. Incompatibile
-                             con \const{MAP\_PRIVATE}. \\ 
+                             con \const{MAP\_PRIVATE}.\\ 
     \const{MAP\_PRIVATE}   & I cambiamenti sulla memoria mappata non vengono
                              riportati sul file. Ne viene fatta una copia
                              privata cui solo il processo chiamante ha
@@ -1582,13 +2274,13 @@ tab.~\ref{tab:file_mmap_flag}.
                              salvate su swap in caso di necessità. Non è
                              specificato se i cambiamenti sul file originale
                              vengano riportati sulla regione
-                             mappata. Incompatibile con \const{MAP\_SHARED}. \\
+                             mappata. Incompatibile con \const{MAP\_SHARED}.\\
     \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
                              \textit{DoS} \itindex{Denial~of~Service~(DoS)}
                              (veniva usato per segnalare che tentativi di
                              scrittura sul file dovevano fallire con
                              \errcode{ETXTBSY}).\\ 
-    \const{MAP\_EXECUTABLE}& Ignorato. \\
+    \const{MAP\_EXECUTABLE}& Ignorato.\\
     \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
                              delle pagine di swap ad uso del meccanismo del
                              \textit{copy on write} \itindex{copy~on~write}
@@ -1596,7 +2288,7 @@ tab.~\ref{tab:file_mmap_flag}.
                              modifiche fatte alla regione mappata, in
                              questo caso dopo una scrittura, se non c'è più
                              memoria disponibile, si ha l'emissione di
-                             un \const{SIGSEGV}. \\
+                             un \const{SIGSEGV}.\\
     \const{MAP\_LOCKED}    & Se impostato impedisce lo swapping delle pagine
                              mappate.\\
     \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} stack. Indica 
@@ -1614,9 +2306,9 @@ tab.~\ref{tab:file_mmap_flag}.
                              richiesto \const{MAP\_FIXED}.\\
     \const{MAP\_POPULATE}  & Esegue il \itindex{prefaulting}
                              \textit{prefaulting} delle pagine di memoria
-                             necessarie alla mappatura. \\
+                             necessarie alla mappatura.\\
     \const{MAP\_NONBLOCK}  & Esegue un \textit{prefaulting} più limitato che
-                             non causa I/O.\footnotemark \\
+                             non causa I/O.\footnotemark\\
 %     \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area
 %                              mappata con \func{mremap}, proposto ma pare non
 %                              implementato.\\
@@ -1645,10 +2337,10 @@ 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.
 
-\footnotetext[20]{Dato che tutti faranno riferimento alle stesse pagine di
+\footnotetext[68]{dato che tutti faranno riferimento alle stesse pagine di
   memoria.}  
 
-\footnotetext[21]{L'uso di questo flag con \const{MAP\_SHARED} è stato
+\footnotetext[69]{l'uso di questo flag con \const{MAP\_SHARED} è stato
   implementato in Linux a partire dai kernel della serie 2.4.x; esso consente
   di creare segmenti di memoria condivisa e torneremo sul suo utilizzo in
   sez.~\ref{sec:ipc_mmap_anonymous}.}
@@ -1659,7 +2351,7 @@ effettive del file o della sezione che si vuole mappare.
 
 \begin{figure}[!htb] 
   \centering
-  \includegraphics[width=12cm]{img/mmap_boundary}
+  \includegraphics[height=6cm]{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}
@@ -1702,7 +2394,7 @@ che sono utilizzabili solo con questa interfaccia.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=12cm]{img/mmap_exceed}
+  \includegraphics[height=6cm]{img/mmap_exceed}
   \caption{Schema della mappatura in memoria di file di dimensioni inferiori
     alla lunghezza richiesta.}
   \label{fig:file_mmap_exceed}
@@ -1759,10 +2451,10 @@ memoria mappata con il file su disco; il suo prototipo 
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EINVAL}] O \param{start} non è multiplo di
+    \item[\errcode{EINVAL}] o \param{start} non è multiplo di
       \const{PAGE\_SIZE}, o si è specificato un valore non valido per
       \param{flags}.
-    \item[\errcode{EFAULT}] L'intervallo specificato non ricade in una zona
+    \item[\errcode{EFAULT}] l'intervallo specificato non ricade in una zona
       precedentemente mappata.
     \end{errlist}
   }
@@ -1789,7 +2481,8 @@ del file aggiornato.
                             siano invalidate.\\
     \hline    
   \end{tabular}
-  \caption{Valori dell'argomento \param{flag} di \func{msync}.}
+  \caption{Le costanti che identificano i bit per la maschera binaria
+    dell'argomento \param{flag} di \func{msync}.}
   \label{tab:file_mmap_rsync}
 \end{table}
 
@@ -1816,7 +2509,7 @@ mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo 
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EINVAL}] L'intervallo specificato non ricade in una zona
+    \item[\errcode{EINVAL}] l'intervallo specificato non ricade in una zona
       precedentemente mappata.
     \end{errlist}
   }
@@ -1970,10 +2663,10 @@ nuova system call, \funcd{remap\_file\_pages}, il cui prototipo 
   
   Permette di rimappare non linearmente un precedente \textit{memory mapping}.
 
-  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+  \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
     errore, nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EINVAL}] Si è usato un valore non valido per uno degli
+    \item[\errcode{EINVAL}] si è usato un valore non valido per uno degli
       argomenti o \param{start} non fa riferimento ad un \textit{memory
         mapping} valido creato con \const{MAP\_SHARED}.
     \end{errlist}
@@ -2032,26 +2725,843 @@ mappatura che gi
 
 \itindend{memory~mapping}
 
+\subsection{I/O vettorizzato: \func{readv} e \func{writev}}
+\label{sec:file_multiple_io}
+
+Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
+serie multipla di operazioni di I/O, come una serie di letture o scritture di
+vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
+una struttura ed essi devono essere caricati o salvati su un file.  Benché
+l'operazione sia facilmente eseguibile attraverso una serie multipla di
+chiamate, ci sono casi in cui si vuole poter contare sulla atomicità delle
+operazioni.
+
+Per questo motivo su BSD 4.2 sono state introdotte due nuove system call,
+\funcd{readv} e \funcd{writev},\footnote{in Linux le due funzioni sono riprese
+  da BSD4.4, esse sono previste anche dallo standard POSIX.1-2001.}  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:
+\begin{functions}
+  \headdecl{sys/uio.h}
+  
+  \funcdecl{int readv(int fd, const struct iovec *vector, int count)} 
+  \funcdecl{int writev(int fd, const struct iovec *vector, int count)} 
+
+  Eseguono rispettivamente una lettura o una scrittura vettorizzata.
+  
+  \bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
+    caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
+    assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
+    argomenti (ad esempio \param{count} è maggiore di \const{IOV\_MAX}).
+  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
+    di avere eseguito una qualunque lettura o scrittura.
+  \item[\errcode{EAGAIN}] \param{fd} è stato aperto in modalità non bloccante e
+    non ci sono dati in lettura.
+  \item[\errcode{EOPNOTSUPP}] la coda delle richieste è momentaneamente piena.
+  \end{errlist}
+  ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
+  (se non sono stati allocati correttamente i buffer specificati nei campi
+  \var{iov\_base}), più gli eventuali errori delle funzioni di lettura e
+  scrittura eseguite su \param{fd}.}
+\end{functions}
+
+Entrambe le funzioni usano una struttura \struct{iovec}, la cui definizione è
+riportata in fig.~\ref{fig:file_iovec}, che definisce dove i dati devono
+essere letti o scritti ed in che quantità. Il primo campo della struttura,
+\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
+\var{iov\_len}, la dimensione dello stesso.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/iovec.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
+    vettorizzato.} 
+  \label{fig:file_iovec}
+\end{figure}
+
+La lista dei buffer da utilizzare viene indicata attraverso l'argomento
+\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
+è specificata dall'argomento \param{count}.\footnote{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
+  POSIX.1-2001.}  Ciascuna struttura dovrà essere inizializzata opportunamente
+per indicare i vari buffer da e verso i quali verrà eseguito il trasferimento
+dei dati. Essi verranno letti (o scritti) nell'ordine in cui li si sono
+specificati nel vettore \param{vector}.
+
+La standardizzazione delle due funzioni all'interno della revisione
+POSIX.1-2001 prevede anche che sia possibile avere un limite al numero di
+elementi del vettore \param{vector}. Qualora questo sussista, esso deve essere
+indicato dal valore dalla costante \const{IOV\_MAX}, definita come le altre
+costanti analoghe (vedi sez.~\ref{sec:sys_limits}) in \file{limits.h}; lo
+stesso valore deve essere ottenibile in esecuzione tramite la funzione
+\func{sysconf} richiedendo l'argomento \const{\_SC\_IOV\_MAX} (vedi
+sez.~\ref{sec:sys_sysconf}).
+
+Nel caso di Linux il limite di sistema è di 1024, però se si usano le
+\acr{glibc} queste forniscono un \textit{wrapper} per le system call che si
+accorge se una operazione supererà il precedente limite, in tal caso i dati
+verranno letti o scritti con le usuali \func{read} e \func{write} usando un
+buffer di dimensioni sufficienti appositamente allocato e sufficiente a
+contenere tutti i dati indicati da \param{vector}. L'operazione avrà successo
+ma si perderà l'atomicità del trasferimento da e verso la destinazione finale.
+
+% TODO verificare cosa succederà a preadv e pwritev o alla nuova niovec
+% vedi http://lwn.net/Articles/164887/
+
+
+\subsection{L'I/O diretto fra file descriptor: \func{sendfile} e \func{splice}}
+\label{sec:file_sendfile_splice}
+
+Uno dei problemi che si presentano nella gestione dell'I/O è quello in cui si
+devono trasferire grandi quantità di dati da un file descriptor ed un altro;
+questo usualmente comporta la lettura dei dati dal primo file descriptor in un
+buffer in memoria, da cui essi vengono poi scritti sul secondo.
+
+Benché il kernel ottimizzi la gestione di questo processo quando si ha a che
+fare con file normali, in generale quando i dati da trasferire sono molti si
+pone il problema di effettuare trasferimenti di grandi quantità di dati da
+kernel space a user space e all'indietro, quando in realtà potrebbe essere più
+efficiente mantenere tutto in kernel space. Tratteremo in questa sezione
+alcune funzioni specialistiche che permettono di ottimizzare le prestazioni in
+questo tipo di situazioni.
+
+La prima funzione che si pone l'obiettivo di ottimizzare il trasferimento dei
+dati fra due file descriptor è \funcd{sendfile};\footnote{la funzione è stata
+  introdotta con i kernel della serie 2.2, e disponibile dalle \acr{glibc}
+  2.1.} la funzione è presente in diverse versioni di Unix,\footnote{la si
+  ritrova ad esempio in FreeBSD, HPUX ed altri Unix.} ma non è presente né in
+POSIX.1-2001 né in altri standard,\footnote{pertanto si eviti di utilizzarla
+  se si devono scrivere programmi portabili.} per cui per essa vengono
+utilizzati prototipi e semantiche differenti; nel caso di Linux il suo
+prototipo è:
+\begin{functions}  
+  \headdecl{sys/sendfile.h} 
 
-\subsection{L'I/O diretto fra file descriptor con \func{sendfile}}
-\label{sec:file_sendfile}
+  \funcdecl{ssize\_t sendfile(int out\_fd, int in\_fd, off\_t *offset, size\_t
+    count)} 
+  
+  Copia dei dati da un file descriptor ad un altro.
+
+  \bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
+    successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+    dei valori:
+    \begin{errlist}
+    \item[\errcode{EAGAIN}] si è impostata la modalità non bloccante su
+      \param{out\_fd} e la scrittura si bloccherebbe.
+    \item[\errcode{EINVAL}] i file descriptor non sono validi, o sono bloccati
+      (vedi sez.~\ref{sec:file_locking}), o \func{mmap} non è disponibile per
+      \param{in\_fd}.
+    \item[\errcode{EIO}] si è avuto un errore di lettura da \param{in\_fd}.
+    \item[\errcode{ENOMEM}] non c'è memoria sufficiente per la lettura da
+      \param{in\_fd}.
+    \end{errlist}
+    ed inoltre \errcode{EBADF} e \errcode{EFAULT}.
+  }
+\end{functions}
 
-Uno dei problemi 
+La funzione copia direttamente \param{count} byte dal file descriptor
+\param{in\_fd} al file descriptor \param{out\_fd}; in caso di successo
+funzione ritorna il numero di byte effettivamente copiati da \param{in\_fd} a
+\param{out\_fd} o $-1$ in caso di errore, come le ordinarie \func{read} e
+\func{write} questo valore può essere inferiore a quanto richiesto con
+\param{count}.
+
+Se il puntatore \param{offset} è nullo la funzione legge i dati a partire
+dalla posizione corrente su \param{in\_fd}, altrimenti verrà usata la
+posizione indicata dal valore puntato da \param{offset}; in questo caso detto
+valore sarà aggiornato, come \textit{value result argument}, per indicare la
+posizione del byte successivo all'ultimo che è stato letto, mentre la
+posizione corrente sul file non sarà modificata. Se invece \param{offset} è
+nullo la posizione corrente sul file sarà aggiornata tenendo conto dei byte
+letti da \param{in\_fd}.
+
+Fino ai kernel della serie 2.4 la funzione è utilizzabile su un qualunque file
+descriptor, e permette di sostituire la invocazione successiva di una
+\func{read} e una \func{write} (e l'allocazione del relativo buffer) con una
+sola chiamata a \funcd{sendfile}. In questo modo si può diminuire il numero di
+chiamate al sistema e risparmiare in trasferimenti di dati da kernel space a
+user space e viceversa.  La massima utilità della funzione si ha comunque per
+il trasferimento di dati da un file su disco ad un socket di
+rete,\footnote{questo è il caso classico del lavoro eseguito da un server web,
+  ed infatti Apache ha una opzione per il supporto esplicito di questa
+  funzione.} dato che in questo caso diventa possibile effettuare il
+trasferimento diretto via DMA dal controller del disco alla scheda di rete,
+senza neanche allocare un buffer nel kernel,\footnote{il meccanismo è detto
+  \textit{zerocopy} in quanto i dati non vengono mai copiati dal kernel, che
+  si limita a programmare solo le operazioni di lettura e scrittura via DMA.}
+ottenendo la massima efficienza possibile senza pesare neanche sul processore.
+
+In seguito però ci si è accorti che, fatta eccezione per il trasferimento
+diretto da file a socket, non sempre \func{sendfile} comportava miglioramenti
+significativi delle prestazioni rispetto all'uso in sequenza di \func{read} e
+\func{write},\footnote{nel caso generico infatti il kernel deve comunque
+  allocare un buffer ed effettuare la copia dei dati, e in tal caso spesso il
+  guadagno ottenibile nel ridurre il numero di chiamate al sistema non
+  compensa le ottimizzazioni che possono essere fatte da una applicazione in
+  user space che ha una conoscenza diretta su come questi sono strutturati.} e
+che anzi in certi casi si potevano avere anche dei peggioramenti.  Questo ha
+portato, per i kernel della serie 2.6,\footnote{per alcune motivazioni di
+  questa scelta si può fare riferimento a quanto illustrato da Linus Torvalds
+  in \href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
+  {\textsf{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.}
+alla decisione di consentire l'uso della funzione soltanto quando il file da
+cui si legge supporta le operazioni di \textit{memory mapping} (vale a dire
+non è un socket) e quello su cui si scrive è un socket; in tutti gli altri
+casi l'uso di \func{sendfile} darà luogo ad un errore di \errcode{EINVAL}.
+
+Nonostante ci possano essere casi in cui \func{sendfile} non migliora le
+prestazioni, le motivazioni addotte non convincono del tutto e resta il dubbio
+se la scelta di disabilitarla sempre per il trasferimento di dati fra file di
+dati sia davvero corretta. Se ci sono peggioramenti di prestazioni infatti si
+può sempre fare ricorso all'uso successivo di, ma lasciare a disposizione la
+funzione consentirebbe se non altro, anche in assenza di guadagni di
+prestazioni, di semplificare la gestione della copia dei dati fra file,
+evitando di dover gestire l'allocazione di un buffer temporaneo per il loro
+trasferimento; inoltre si avrebbe comunque il vantaggio di evitare inutili
+trasferimenti di dati da kernel space a user space e viceversa.
+
+Questo dubbio si può comunque ritenere superato con l'introduzione, avvenuto a
+partire dal kernel 2.6.17, della nuova system call \func{splice}. Lo scopo di
+questa funzione è quello di fornire un meccanismo generico per il
+trasferimento di dati da o verso un file utilizzando un buffer gestito
+internamente dal kernel. Descritta in questi termini \func{splice} sembra
+semplicemente un ``\textsl{dimezzamento}'' di \func{sendfile}.\footnote{nel
+  senso che un trasferimento di dati fra due file con \func{sendfile} non
+  sarebbe altro che la lettura degli stessi su un buffer seguita dalla
+  relativa scrittura, cosa che in questo caso si dovrebbe eseguire con due
+  chiamate a \func{splice}.} In realtà le due system call sono profondamente
+diverse nel loro meccanismo di funzionamento;\footnote{questo fino al kernel
+  2.6.23, dove \func{sendfile} è stata reimplementata in termini di
+  \func{splice}, pur mantenendo disponibile la stessa interfaccia verso l'user
+  space.} \func{sendfile} infatti, come accennato, non necessita di avere a
+disposizione un buffer interno, perché esegue un trasferimento diretto di
+dati; questo la rende in generale più efficiente, ma anche limitata nelle sue
+applicazioni, dato che questo tipo di trasferimento è possibile solo in casi
+specifici.\footnote{e nel caso di Linux questi sono anche solo quelli in cui
+  essa può essere effettivamente utilizzata.}
+
+Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
+  realtà la proposta originale di Larry Mc Voy non differisce poi tanto negli
+  scopi da \func{sendfile}, quello che rende \func{splice} davvero diversa è
+  stata la reinterpretazione che ne è stata fatta nell'implementazione su
+  Linux realizzata da Jens Anxboe, concetti che sono esposti sinteticamente
+  dallo stesso Linus Torvalds in \href{http://kerneltrap.org/node/6505}
+  {\textsf{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una
+funzione che consente di fare in maniera del tutto generica delle operazioni
+di trasferimento di dati fra un file e un buffer gestito interamente in kernel
+space. In questo caso il cuore della funzione (e delle affini \func{vmsplice}
+e \func{tee}, che tratteremo più avanti) è appunto l'uso di un buffer in
+kernel space, e questo è anche quello che ne ha semplificato l'adozione,
+perché l'infrastruttura per la gestione di un tale buffer è presente fin dagli
+albori di Unix per la realizzazione delle \textit{pipe} (vedi
+sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale allora \func{splice}
+non è altro che una diversa interfaccia (rispetto alle \textit{pipe}) con cui
+utilizzare in user space l'oggetto ``\textsl{buffer in kernel space}''.
+
+Così se per una \textit{pipe} o una \textit{fifo} il buffer viene utilizzato
+come area di memoria (vedi fig.~\ref{fig:ipc_pipe_singular}) dove appoggiare i
+dati che vengono trasferiti da un capo all'altro della stessa per creare un
+meccanismo di comunicazione fra processi, nel caso di \func{splice} il buffer
+viene usato o come fonte dei dati che saranno scritti su un file, o come
+destinazione dei dati che vengono letti da un file. La funzione \funcd{splice}
+fornisce quindi una interfaccia generica che consente di trasferire dati da un
+buffer ad un file o viceversa; il suo prototipo, accessibile solo dopo aver
+definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa
+  funzione non è contemplata da nessuno standard, è presente solo su Linux, e
+  pertanto deve essere evitata se si vogliono scrivere programmi portabili.}
+è il seguente:
+\begin{functions}  
+  \headdecl{fcntl.h} 
 
-NdA è da finire, sul perché non è abilitata fra file vedi:
+  \funcdecl{long splice(int fd\_in, off\_t *off\_in, int fd\_out, off\_t
+    *off\_out, size\_t len, unsigned int flags)}
+  
+  Trasferisce dati da un file verso una pipe o viceversa.
 
-\href{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}
-{\texttt{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}
-% TODO documentare la funzione sendfile
+  \bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
+    successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+    dei valori:
+    \begin{errlist}
+    \item[\errcode{EBADF}] uno o entrambi fra \param{fd\_in} e \param{fd\_out}
+      non sono file descriptor validi o, rispettivamente, non sono stati
+      aperti in lettura o scrittura.
+    \item[\errcode{EINVAL}] il filesystem su cui si opera non supporta
+      \func{splice}, oppure nessuno dei file descriptor è una pipe, oppure si
+      è dato un valore a \param{off\_in} o \param{off\_out} ma il
+      corrispondente file è un dispositivo che non supporta la funzione
+      \func{seek}.
+    \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione
+      richiesta.
+    \item[\errcode{ESPIPE}] o \param{off\_in} o \param{off\_out} non sono
+      \const{NULL} ma il corrispondente file descriptor è una \textit{pipe}.
+    \end{errlist}
+  }
+\end{functions}
 
+La funzione esegue un trasferimento di \param{len} byte dal file descriptor
+\param{fd\_in} al file descriptor \param{fd\_out}, uno dei quali deve essere
+una \textit{pipe}; l'altro file descriptor può essere
+qualunque.\footnote{questo significa che può essere, oltre che un file di
+  dati, anche un altra \textit{pipe}, o un socket.}  Come accennato una
+\textit{pipe} non è altro che un buffer in kernel space, per cui a seconda che
+essa sia usata per \param{fd\_in} o \param{fd\_out} si avrà rispettivamente la
+copia dei dati dal buffer al file o viceversa. 
+
+In caso di successo la funzione ritorna il numero di byte trasferiti, che può
+essere, come per le normali funzioni di lettura e scrittura su file, inferiore
+a quelli richiesti; un valore negativo indicherà un errore mentre un valore
+nullo indicherà che non ci sono dati da trasferire (ad esempio si è giunti
+alla fine del file in lettura). Si tenga presente che, a seconda del verso del
+trasferimento dei dati, la funzione si comporta nei confronti del file
+descriptor che fa riferimento al file ordinario, come \func{read} o
+\func{write}, e pertanto potrà anche bloccarsi (a meno che non si sia aperto
+il suddetto file in modalità non bloccante).
+
+I due argomenti \param{off\_in} e \param{off\_out} consentono di specificare,
+come per l'analogo \param{offset} di \func{sendfile}, la posizione all'interno
+del file da cui partire per il trasferimento dei dati. Come per
+\func{sendfile} un valore nullo indica di usare la posizione corrente sul
+file, ed essa sarà aggiornata automaticamente secondo il numero di byte
+trasferiti. Un valore non nullo invece deve essere un puntatore ad una
+variabile intera che indica la posizione da usare; questa verrà aggiornata, al
+ritorno della funzione, al byte successivo all'ultimo byte trasferito.
+Ovviamente soltanto uno di questi due argomenti, e più precisamente quello che
+fa riferimento al file descriptor non associato alla \textit{pipe}, può essere
+specificato come valore non nullo.
+
+Infine l'argomento \param{flags} consente di controllare alcune
+caratteristiche del funzionamento della funzione; il contenuto è una maschera
+binaria e deve essere specificato come OR aritmetico dei valori riportati in
+tab.~\ref{tab:splice_flag}. Alcuni di questi valori vengono utilizzati anche
+dalle funzioni \func{vmsplice} e \func{tee} per cui la tabella riporta le
+descrizioni complete di tutti i valori possibili anche quando, come per
+\const{SPLICE\_F\_GIFT}, questi non hanno effetto su \func{splice}.
 
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{SPLICE\_F\_MOVE}    & Suggerisce al kernel di spostare le pagine
+                                 di memoria contenenti i dati invece di
+                                 copiarle;\footnotemark viene usato soltanto
+                                 da \func{splice}.\\ 
+    \const{SPLICE\_F\_NONBLOCK}& Richiede di operare in modalità non
+                                 bloccante; questo flag influisce solo sulle
+                                 operazioni che riguardano l'I/O da e verso la
+                                 \textit{pipe}. Nel caso di \func{splice}
+                                 questo significa che la funzione potrà
+                                 comunque bloccarsi nell'accesso agli altri
+                                 file descriptor (a meno che anch'essi non
+                                 siano stati aperti in modalità non
+                                 bloccante).\\
+    \const{SPLICE\_F\_MORE}    & Indica al kernel che ci sarà l'invio di
+                                 ulteriori dati in una \func{splice}
+                                 successiva, questo è un suggerimento utile
+                                 che viene usato quando \param{fd\_out} è un
+                                 socket.\footnotemark Attualmente viene usato
+                                 solo da \func{splice}, potrà essere
+                                 implementato in futuro anche per
+                                 \func{vmsplice} e \func{tee}.\\
+    \const{SPLICE\_F\_GIFT}    & Le pagine di memoria utente sono
+                                 ``\textsl{donate}'' al kernel;\footnotemark
+                                 se impostato una seguente \func{splice} che
+                                 usa \const{SPLICE\_F\_MOVE} potrà spostare le 
+                                 pagine con successo, altrimenti esse dovranno
+                                 essere copiate; per usare questa opzione i
+                                 dati dovranno essere opportunamente allineati
+                                 in posizione ed in dimensione alle pagine di
+                                 memoria. Viene usato soltanto da
+                                 \func{vmsplice}.\\
+    \hline
+  \end{tabular}
+  \caption{Le costanti che identificano i bit della maschera binaria
+    dell'argomento \param{flags} di \func{splice}, \func{vmsplice} e
+    \func{tee}.} 
+  \label{tab:splice_flag}
+\end{table}
 
-% i raw device 
-%\subsection{I \textit{raw} device}
-%\label{sec:file_raw_device}
-%
-% TODO i raw device
+\footnotetext{per una maggiore efficienza \func{splice} usa quando possibile i
+  meccanismi della memoria virtuale per eseguire i trasferimenti di dati (in
+  maniera analoga a \func{mmap}), qualora le pagine non possano essere
+  spostate dalla pipe o il buffer non corrisponda a pagine intere esse saranno
+  comunque copiate.}
+
+\footnotetext{questa opzione consente di utilizzare delle opzioni di gestione
+  dei socket che permettono di ottimizzare le trasmissioni via rete, si veda
+  la descrizione di \const{TCP\_CORK} in sez.~\ref{sec:sock_tcp_udp_options} e
+  quella di \const{MSG\_MORE} in sez.~\ref{sec:net_sendmsg}.}
+
+\footnotetext{questo significa che la cache delle pagine e i dati su disco
+  potranno differire, e che l'applicazione non potrà modificare quest'area di
+  memoria.}
+
+Per capire meglio il funzionamento di \func{splice} vediamo un esempio con un
+semplice programma che usa questa funzione per effettuare la copia di un file
+su un altro senza utilizzare buffer in user space. Il programma si chiama
+\texttt{splicecp.c} ed il codice completo è disponibile coi sorgenti allegati
+alla guida, il corpo principale del programma, che non contiene la sezione di
+gestione delle opzioni e le funzioni di ausilio è riportato in
+fig.~\ref{fig:splice_example}.
+
+Lo scopo del programma è quello di eseguire la copia dei con \func{splice},
+questo significa che si dovrà usare la funzione due volte, prima per leggere i
+dati e poi per scriverli, appoggiandosi ad un buffer in kernel space (vale a
+dire ad una \textit{pipe}); lo schema del flusso dei dati è illustrato in
+fig.~\ref{fig:splicecp_data_flux}. 
 
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=6cm]{img/splice_copy}
+  \caption{Struttura del flusso di dati usato dal programma \texttt{splicecp}.}
+  \label{fig:splicecp_data_flux}
+\end{figure}
+
+Una volta trattate le opzioni il programma verifica che restino
+(\texttt{\small 13--16}) i due argomenti che indicano il file sorgente ed il
+file destinazione. Il passo successivo è aprire il file sorgente
+(\texttt{\small 18--22}), quello di destinazione (\texttt{\small 23--27}) ed
+infine (\texttt{\small 28--31}) la \textit{pipe} che verrà usata come buffer.
+
+\begin{figure}[!phtb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/splicecp.c}
+  \end{minipage}
+  \normalsize
+  \caption{Esempio di codice che usa \func{splice} per effettuare la copia di
+    un file.}
+  \label{fig:splice_example}
+\end{figure}
+
+Il ciclo principale (\texttt{\small 33--58}) inizia con la lettura dal file
+sorgente tramite la prima \func{splice} (\texttt{\small 34--35}), in questo
+caso si è usato come primo argomento il file descriptor del file sorgente e
+come terzo quello del capo in scrittura della \textit{pipe} (il funzionamento
+delle \textit{pipe} e l'uso della coppia di file descriptor ad esse associati
+è trattato in dettaglio in sez.~\ref{sec:ipc_unix}; non ne parleremo qui dato
+che nell'ottica dell'uso di \func{splice} questa operazione corrisponde
+semplicemente al trasferimento dei dati dal file al buffer).
+
+La lettura viene eseguita in blocchi pari alla dimensione specificata
+dall'opzione \texttt{-s} (il default è 4096); essendo in questo caso
+\func{splice} equivalente ad una \func{read} sul file, se ne controlla il
+valore di uscita in \var{nread} che indica quanti byte sono stati letti, se
+detto valore è nullo (\texttt{\small 36}) questo significa che si è giunti
+alla fine del file sorgente e pertanto l'operazione di copia è conclusa e si
+può uscire dal ciclo arrivando alla conclusione del programma (\texttt{\small
+  59}). In caso di valore negativo (\texttt{\small 37--44}) c'è stato un
+errore ed allora si ripete la lettura (\texttt{\small 36}) se questo è dovuto
+ad una interruzione, o altrimenti si esce con un messaggio di errore
+(\texttt{\small 41--43}).
+
+Una volta completata con successo la lettura si avvia il ciclo di scrittura
+(\texttt{\small 45--57}); questo inizia (\texttt{\small 46--47}) con la
+seconda \func{splice} che cerca di scrivere gli \var{nread} byte letti, si
+noti come in questo caso il primo argomento faccia di nuovo riferimento alla
+\textit{pipe} (in questo caso si usa il capo in lettura, per i dettagli si
+veda al solito sez.~\ref{sec:ipc_unix}) mentre il terzo sia il file descriptor
+del file di destinazione.
+
+Di nuovo si controlla il numero di byte effettivamente scritti restituito in
+\var{nwrite} e in caso di errore al solito si ripete la scrittura se questo è
+dovuto a una interruzione o si esce con un messaggio negli altri casi
+(\texttt{\small 48--55}). Infine si chiude il ciclo di scrittura sottraendo
+(\texttt{\small 57}) il numero di byte scritti a quelli di cui è richiesta la
+scrittura,\footnote{in questa parte del ciclo \var{nread}, il cui valore
+  iniziale è dato dai byte letti dalla precedente chiamata a \func{splice},
+  viene ad assumere il significato di byte da scrivere.} così che il ciclo di
+scrittura venga ripetuto fintanto che il valore risultante sia maggiore di
+zero, indice che la chiamata a \func{splice} non ha esaurito tutti i dati
+presenti sul buffer.
+
+Si noti come il programma sia concettualmente identico a quello che si sarebbe
+scritto usando \func{read} al posto della prima \func{splice} e \func{write}
+al posto della seconda, utilizzando un buffer in user space per eseguire la
+copia dei dati, solo che in questo caso non è stato necessario allocare nessun
+buffer e non si è trasferito nessun dato in user space.
+
+Si noti anche come si sia usata la combinazione \texttt{SPLICE\_F\_MOVE |
+  SPLICE\_F\_MORE } per l'argomento \param{flags} di \func{splice}, infatti
+anche se un valore nullo avrebbe dato gli stessi risultati, l'uso di questi
+flag, che si ricordi servono solo a dare suggerimenti al kernel, permette in
+genere di migliorare le prestazioni.
+
+Come accennato con l'introduzione di \func{splice} sono state realizzate altre
+due system call, \func{vmsplice} e \func{tee}, che utilizzano la stessa
+infrastruttura e si basano sullo stesso concetto di manipolazione e
+trasferimento di dati attraverso un buffer in kernel space; benché queste non
+attengono strettamente ad operazioni di trasferimento dati fra file
+descriptor, le tratteremo qui.
+
+La prima funzione, \funcd{vmsplice}, è la più simile a \func{splice} e come
+indica il suo nome consente di trasferire i dati dalla memoria di un processo
+verso una \textit{pipe}, il suo prototipo è:
+\begin{functions}  
+  \headdecl{fcntl.h} 
+  \headdecl{sys/uio.h}
+
+  \funcdecl{long vmsplice(int fd, const struct iovec *iov, unsigned long
+    nr\_segs, unsigned int flags)}
+  
+  Trasferisce dati dalla memoria di un processo verso una \textit{pipe}.
+
+  \bodydesc{La funzione restituisce il numero di byte trasferiti in caso di
+    successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+    dei valori:
+    \begin{errlist}
+    \item[\errcode{EBADF}] o \param{fd} non è un file descriptor valido o non
+      fa riferimento ad una \textit{pipe}.
+    \item[\errcode{EINVAL}] si è usato un valore nullo per \param{nr\_segs}
+      oppure si è usato \const{SPLICE\_F\_GIFT} ma la memoria non è allineata.
+    \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione
+      richiesta.
+    \end{errlist}
+  }
+\end{functions}
+
+La \textit{pipe} dovrà essere specificata tramite il file descriptor
+corrispondente al suo capo aperto in scrittura (di nuovo si faccia riferimento
+a sez.~\ref{sec:ipc_unix}), mentre per indicare quali zone di memoria devono
+essere trasferita si deve utilizzare un vettore di strutture \struct{iovec}
+(vedi fig.~\ref{fig:file_iovec}), con le stesse con cui le si usano per l'I/O
+vettorizzato; le dimensioni del suddetto vettore devono essere passate
+nell'argomento \param{nr\_segs} che indica il numero di segmenti di memoria da
+trasferire.  Sia per il vettore che per il valore massimo di \param{nr\_segs}
+valgono le stesse limitazioni illustrate in sez.~\ref{sec:file_multiple_io}.
+
+In caso di successo la funzione ritorna il numero di byte trasferiti sulla
+pipe, in generale (se i dati una volta creati non devono essere riutilizzati)
+è opportuno utilizzare il flag \const{SPLICE\_F\_GIFT}; questo fa si che il
+kernel possa rimuovere le relative pagine dallo spazio degli indirizzi del
+processo, e scaricarle nella cache, così che queste possono essere utilizzate
+immediatamente senza necessità di eseguire una copia dei dati che contengono.
+
+La seconda funzione aggiunta insieme a \func{splice} è \func{tee}, che deve il
+suo nome all'omonimo comando in user space, perché in analogia con questo
+permette di duplicare i dati in ingresso su una \textit{pipe} su un'altra
+\textit{pipe}. In sostanza, sempre nell'ottica della manipolazione dei dati su
+dei buffer in kernel space, la funzione consente di eseguire una copia del
+contenuto del buffer stesso. Il prototipo di \funcd{tee} è il seguente:
+\begin{functions}  
+  \headdecl{fcntl.h} 
+
+  \funcdecl{long tee(int fd\_in, int fd\_out, size\_t len, unsigned int
+    flags)}
+  
+  Duplica \param{len} byte da una \textit{pipe} ad un'altra.
+
+  \bodydesc{La funzione restituisce il numero di byte copiati in caso di
+    successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno
+    dei valori:
+    \begin{errlist}
+    \item[\errcode{EINVAL}] o uno fra \param{fd\_in} e \param{fd\_out} non fa
+      riferimento ad una \textit{pipe} o entrambi fanno riferimento alla
+      stessa \textit{pipe}.
+    \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'operazione
+      richiesta.
+    \end{errlist}
+  }
+\end{functions}
+
+La funzione copia \param{len} byte del contenuto di una \textit{pipe} su di
+un'altra; \param{fd\_in} deve essere il capo in lettura della \textit{pipe}
+sorgente e \param{fd\_out} il capo in scrittura della \textit{pipe}
+destinazione; a differenza di quanto avviene con \func{read} i dati letti con
+\func{tee} da \func{fd\_in} non vengono \textsl{consumati} e restano
+disponibili sulla \textit{pipe} per una successiva lettura (di nuovo per il
+comportamento delle \textit{pipe} si veda sez.~\ref{sec:ipc_unix}).
+
+La funzione restituisce il numero di byte copiati da una \textit{pipe}
+all'altra (o $-1$ in caso di errore), un valore nullo indica che non ci sono
+byte disponibili da copiare e che il capo in scrittura della pipe è stato
+chiuso.\footnote{si tenga presente però che questo non avviene se si è
+  impostato il flag \const{SPLICE\_F\_NONBLOCK}, in tal caso infatti si
+  avrebbe un errore di \errcode{EAGAIN}.} Un esempio di realizzazione del
+comando \texttt{tee} usando questa funzione, ripreso da quello fornito nella
+pagina di manuale e dall'esempio allegato al patch originale, è riportato in
+fig.~\ref{fig:tee_example}. Il programma consente di copiare il contenuto
+dello standard input sullo standard output e su un file specificato come
+argomento, il codice completo si trova nel file \texttt{tee.c} dei sorgenti
+allegati alla guida.
+
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includecodesample{listati/tee.c}
+  \end{minipage}
+  \normalsize
+  \caption{Esempio di codice che usa \func{tee} per copiare i dati dello
+    standard input sullo standard output e su un file.}
+  \label{fig:tee_example}
+\end{figure}
+
+La prima parte del programma (\texttt{\small 10--35}) si cura semplicemente di
+controllare (\texttt{\small 11--14}) che sia stato fornito almeno un argomento
+(il nome del file su cui scrivere), di aprirlo ({\small 15--19}) e che sia lo
+standard input (\texttt{\small 20--27}) che lo standard output (\texttt{\small
+  28--35}) corrispondano ad una \textit{pipe}.
+
+Il ciclo principale (\texttt{\small 37--58}) inizia con la chiamata a
+\func{tee} che duplica il contenuto dello standard input sullo standard output
+(\texttt{\small 39}), questa parte è del tutto analoga ad una lettura ed
+infatti come nell'esempio di fig.~\ref{fig:splice_example} si controlla il
+valore di ritorno della funzione in \var{len}; se questo è nullo significa che
+non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 40}), se
+è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è
+dovuto ad una interruzione (\texttt{\small 42--44}) o si stampa un messaggio
+di errore e si esce negli altri casi (\texttt{\small 44--47}).
+
+Una volta completata la copia dei dati sullo standard output si possono
+estrarre dalla standard input e scrivere sul file, di nuovo su usa un ciclo di
+scrittura (\texttt{\small 50--58}) in cui si ripete una chiamata a
+\func{splice} (\texttt{\small 51}) fintanto che non si sono scritti tutti i
+\var{len} byte copiati in precedenza con \func{tee} (il funzionamento è
+identico all'analogo ciclo di scrittura del precedente esempio di
+fig.~\ref{fig:splice_example}).
+
+Infine una nota finale riguardo \func{splice}, \func{vmsplice} e \func{tee}:
+occorre sottolineare che benché finora si sia parlato di trasferimenti o copie
+di dati in realtà nella implementazione di queste system call non è affatto
+detto che i dati vengono effettivamente spostati o copiati, il kernel infatti
+realizza le \textit{pipe} come un insieme di puntatori\footnote{per essere
+  precisi si tratta di un semplice buffer circolare, un buon articolo sul tema
+  si trova su \href{http://lwn.net/Articles/118750/}
+  {\textsf{http://lwn.net/Articles/118750/}}.}  alle pagine di memoria interna
+che contengono i dati, per questo una volta che i dati sono presenti nella
+memoria del kernel tutto quello che viene fatto è creare i suddetti puntatori
+ed aumentare il numero di referenze; questo significa che anche con \func{tee}
+non viene mai copiato nessun byte, vengono semplicemente copiati i puntatori.
+
+
+
+\subsection{Gestione avanzata dell'accesso ai dati dei file}
+\label{sec:file_fadvise}
+
+Nell'uso generico dell'interfaccia per l'accesso al contenuto dei file le
+operazioni di lettura e scrittura non necessitano di nessun intervento di
+supervisione da parte dei programmi, si eseguirà una \func{read} o una
+\func{write}, i dati verranno passati al kernel che provvederà ad effettuare
+tutte le operazioni (e a gestire il \textit{caching} dei dati) per portarle a
+termine in quello che ritiene essere il modo più efficiente.
+
+Il problema è che il concetto di migliore efficienza impiegato dal kernel è
+relativo all'uso generico, mentre esistono molti casi in cui ci sono esigenze
+specifiche dei singoli programmi, che avendo una conoscenza diretta di come
+verranno usati i file, possono necessitare di effettuare delle ottimizzazioni
+specifiche, relative alle proprie modalità di I/O sugli stessi. Tratteremo in
+questa sezione una serie funzioni che consentono ai programmi di ottimizzare
+il loro accesso ai dati dei file e controllare la gestione del relativo
+\textit{caching}.
+
+Una prima funzione che può essere utilizzata per modificare la gestione
+ordinaria dell'I/O su un file è \funcd{readahead},\footnote{questa è una
+  funzione specifica di Linux, introdotta con il kernel 2.4.13, e non deve
+  essere usata se si vogliono scrivere programmi portabili.} che consente di
+richiedere una lettura anticipata del contenuto dello stesso in cache, così
+che le seguenti operazioni di lettura non debbano subire il ritardo dovuto
+all'accesso al disco; il suo prototipo è:
+\begin{functions}
+  \headdecl{fcntl.h}
+
+  \funcdecl{ssize\_t readahead(int fd, off64\_t *offset, size\_t count)}
+  
+  Esegue una lettura preventiva del contenuto di un file in cache.
+
+  \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
+      valido o non è aperto in lettura.
+    \item[\errcode{EINVAL}] l'argomento \param{fd} si riferisce ad un tipo di
+      file che non supporta l'operazione (come una pipe o un socket).
+    \end{errlist}
+  }
+\end{functions}
+
+La funzione richiede che venga letto in anticipo il contenuto del file
+\param{fd} a partire dalla posizione \param{offset} e per un ammontare di
+\param{count} byte, in modo da portarlo in cache.  La funzione usa la
+\index{memoria~virtuale} memoria virtuale ed il meccanismo della
+\index{paginazione} paginazione per cui la lettura viene eseguita in blocchi
+corrispondenti alle dimensioni delle pagine di memoria, ed i valori di
+\param{offset} e \param{count} arrotondati di conseguenza.
+
+La funzione estende quello che è un comportamento normale del
+kernel\footnote{per ottimizzare gli accessi al disco il kernel quando si legge
+  un file, aspettandosi che l'accesso prosegua, esegue sempre una lettura
+  anticipata di una certa quantità di dati; questo meccanismo viene chiamato
+  \textit{readahead}, da cui deriva il nome della funzione.} effettuando la
+lettura in cache della sezione richiesta e bloccandosi fintanto che questa non
+viene completata.  La posizione corrente sul file non viene modificata ed
+indipendentemente da quanto indicato con \param{count} la lettura dei dati si
+interrompe una volta raggiunta la fine del file.
+
+Si può utilizzare questa funzione per velocizzare le operazioni di lettura
+all'interno del programma tutte le volte che si conosce in anticipo quanti
+dati saranno necessari in seguito. Si potrà così concentrare in un unico
+momento (ad esempio in fase di inizializzazione) la lettura, così da ottenere
+una migliore risposta nelle operazioni successive.
+
+Il concetto di \func{readahead} viene generalizzato nello standard
+POSIX.1-2001 dalla funzione \funcd{posix\_fadvise},\footnote{anche se
+  l'argomento \param{len} è stato modificato da \ctyp{size\_t} a \ctyp{off\_t}
+  nella revisione POSIX.1-2003 TC5.} che consente di ``\textsl{avvisare}'' il
+kernel sulle modalità con cui si intende accedere nel futuro ad una certa
+porzione di un file,\footnote{la funzione però è stata introdotta su Linux
+  solo a partire dal kernel 2.5.60.} così che esso possa provvedere le
+opportune ottimizzazioni; il suo prototipo, che può è disponibile solo se si
+definisce la macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è:
+\begin{functions}  
+  \headdecl{fcntl.h} 
+
+  \funcdecl{int posix\_fadvise(int fd, off\_t offset, off\_t len, int advice)}
+  
+  Dichiara al kernel le future modalità di accesso ad un file.
+
+  \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di
+    errore, nel qual caso \var{errno} assumerà uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
+      valido.
+    \item[\errcode{EINVAL}] il valore di \param{advice} non è valido o
+      \param{fd} si riferisce ad un tipo di file che non supporta l'operazione
+      (come una pipe o un socket).
+    \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una pipe o
+      un socket (ma su Linux viene restituito \errcode{EINVAL}).
+    \end{errlist}
+  }
+\end{functions}
+
+La funzione dichiara al kernel le modalità con cui intende accedere alla
+regione del file indicato da \param{fd} che inizia alla posizione
+\param{offset} e si estende per \param{len} byte. Se per \param{len} si usa un
+valore nullo la regione coperta sarà da \param{offset} alla fine del
+file.\footnote{questo è vero solo per le versioni più recenti, fino al kernel
+  2.6.6 il valore nullo veniva interpretato letteralmente.} Le modalità sono
+indicate dall'argomento \param{advice} che è una maschera binaria dei valori
+illustrati in tab.~\ref{tab:posix_fadvise_flag}. Si tenga presente comunque
+che la funzione dà soltanto un avvertimento, non esiste nessun vincolo per il
+kernel, che utilizza semplicemente l'informazione.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{POSIX\_FADV\_NORMAL}  & Non ci sono avvisi specifici da fare
+                                   riguardo le modalità di accesso, il
+                                   comportamento sarà identico a quello che si
+                                   avrebbe senza nessun avviso.\\ 
+    \const{POSIX\_FADV\_SEQUENTIAL}& L'applicazione si aspetta di accedere di
+                                   accedere ai dati specificati in maniera
+                                   sequenziale, a partire dalle posizioni più
+                                   basse.\\ 
+    \const{POSIX\_FADV\_RANDOM}  & I dati saranno letti in maniera
+                                   completamente causale.\\
+    \const{POSIX\_FADV\_NOREUSE} & I dati saranno acceduti una sola volta.\\ 
+    \const{POSIX\_FADV\_WILLNEED}& I dati saranno acceduti a breve.\\ 
+    \const{POSIX\_FADV\_DONTNEED}& I dati non saranno acceduti a breve.\\ 
+    \hline
+  \end{tabular}
+  \caption{Valori dei bit dell'argomento \param{advice} di
+    \func{posix\_fadvise} che indicano la modalità con cui si intende accedere
+    ad un file.}
+  \label{tab:posix_fadvise_flag}
+\end{table}
+
+Anche \func{posix\_fadvise} si appoggia al sistema della memoria virtuale ed
+al meccanismo standard del \textit{readahead} utilizzato dal kernel; in
+particolare con \const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la dimensione
+dell'ammontare di dati letti preventivamente rispetto al default, aspettandosi
+appunto una lettura sequenziale che li utilizzerà, mentre con
+\const{POSIX\_FADV\_RANDOM} si disabilita del tutto il suddetto meccanismo,
+dato che con un accesso del tutto casuale è inutile mettersi a leggere i dati
+immediatamente successivi gli attuali; infine l'uso di
+\const{POSIX\_FADV\_NORMAL} consente di riportarsi al comportamento di
+default.
+
+Le due modalità \const{POSIX\_FADV\_NOREUSE} e \const{POSIX\_FADV\_WILLNEED}
+danno invece inizio ad una lettura in cache della regione del file indicata.
+La quantità di dati che verranno letti è ovviamente limitata in base al carico
+che si viene a creare sul sistema della memoria virtuale, ma in genere una
+lettura di qualche megabyte viene sempre soddisfatta (ed un valore superiore è
+solo raramente di qualche utilità). In particolare l'uso di
+\const{POSIX\_FADV\_WILLNEED} si può considerare l'equivalente POSIX di
+\func{readahead}.
+
+Infine con \const{POSIX\_FADV\_DONTNEED} si dice al kernel di liberare le
+pagine di cache occupate dai dati presenti nella regione di file indicata.
+Questa è una indicazione utile che permette di alleggerire il carico sulla
+cache, ed un programma può utilizzare periodicamente questa funzione per
+liberare pagine di memoria da dati che non sono più utilizzati per far posto a
+nuovi dati utili.\footnote{la pagina di manuale riporta l'esempio dello
+  streaming di file di grosse dimensioni, dove le pagine occupate dai dati già
+  inviati possono essere tranquillamente scartate.}
+
+Sia \func{posix\_fadvise} che \func{readahead} attengono alla ottimizzazione
+dell'accesso in lettura; lo standard POSIX.1-2001 prevede anche una funzione
+specifica per le operazioni di scrittura, \func{posix\_fallocate},\footnote{la
+  funzione è stata introdotta a partire dalle glibc 2.1.94.} che consente di
+preallocare dello spazio disco per assicurarsi che una seguente scrittura non
+fallisca, il suo prototipo, anch'esso disponibile solo se si definisce la
+macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è:
+\begin{functions}  
+  \headdecl{fcntl.h} 
+
+  \funcdecl{int posix\_fallocate(int fd, off\_t offset, off\_t len)}
+  
+  Richiede la allocazione di spazio disco per un file.
+
+  \bodydesc{La funzione restituisce 0 in caso di successo e direttamente un
+    codice di errore, in caso di fallimento, in questo caso \var{errno} non
+    viene impostata, ma sarà restituito direttamente uno dei valori:
+    \begin{errlist}
+    \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
+      valido o non è aperto in scrittura.
+    \item[\errcode{EINVAL}] o \param{offset} o \param{len} sono minori di
+      zero.
+    \item[\errcode{EFBIG}] il valore di (\param{offset} + \param{len}) eccede
+      la dimensione massima consentita per un file.
+    \item[\errcode{ENODEV}] l'argomento \param{fd} non fa riferimento ad un
+      file regolare.
+    \item[\errcode{ENOSPC}] non c'è sufficiente spazio disco per eseguire
+      l'operazione. 
+    \item[\errcode{ESPIPE}] l'argomento \param{fd} è una pipe.
+  \end{errlist}
+  }
+\end{functions}
+
+La funzione si assicura che venga allocato sufficiente spazio disco perché sia
+possibile scrivere sul file indicato dall'argomento \param{fd} nella regione
+che inizia dalla posizione \param{offset} e si estende per \param{len} byte;
+se questa si estende oltre la fine del file le dimensioni di quest'ultimo
+saranno incrementate di conseguenza. Dopo aver eseguito con successo la
+funzione è garantito che una scrittura nella regione indicata non fallirà per
+mancanza di spazio disco.
+
+
+% TODO documentare \func{posix\_fadvise}
+% vedi http://insights.oetiker.ch/linux/fadvise.html
+% questo tread? http://www.ussg.iu.edu/hypermail/linux/kernel/0703.1/0032.html
+
+% TODO documentare \func{fallocate}, introdotta con il 2.6.23
+% vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/
+% http://kernelnewbies.org/Linux_2_6_23
 
 %\subsection{L'utilizzo delle porte di I/O}
 %\label{sec:file_io_port}
@@ -2062,6 +3572,7 @@ NdA 
 
 
 
+
 \section{Il file locking}
 \label{sec:file_locking}
 
@@ -2082,7 +3593,7 @@ in cui diversi processi scrivono, mescolando in maniera imprevedibile il loro
 output sul file.
 
 In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le \textit{race condition} \itindex{race~condition}, attraverso una
+evitare le \itindex{race~condition} \textit{race condition}, attraverso una
 serie di funzioni che permettono di bloccare l'accesso al file da parte di
 altri processi, così da evitare le sovrapposizioni, e garantire la atomicità
 delle operazioni di scrittura.
@@ -2193,7 +3704,7 @@ rimuovere un \textit{file lock} 
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore, nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EWOULDBLOCK}] Il file ha già un blocco attivo, e si è
+    \item[\errcode{EWOULDBLOCK}] il file ha già un blocco attivo, e si è
       specificato \const{LOCK\_NB}.
     \end{errlist}
   }
@@ -2329,17 +3840,17 @@ essa viene usata solo secondo il prototipo:
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore, nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EACCES}] L'operazione è proibita per la presenza di
+    \item[\errcode{EACCES}] l'operazione è proibita per la presenza di
       \textit{file lock} da parte di altri processi.
-    \item[\errcode{ENOLCK}] Il sistema non ha le risorse per il locking: ci
+    \item[\errcode{ENOLCK}] il sistema non ha le risorse per il locking: ci
       sono troppi segmenti di lock aperti, si è esaurita la tabella dei lock,
       o il protocollo per il locking remoto è fallito.
-    \item[\errcode{EDEADLK}] Si è richiesto un lock su una regione bloccata da
+    \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
       \itindex{deadlock} \textit{deadlock}. Non è garantito che il sistema
       riconosca sempre questa situazione.
-    \item[\errcode{EINTR}] La funzione è stata interrotta da un segnale prima
+    \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima
       di poter acquisire un lock.
     \end{errlist}
     ed inoltre \errval{EBADF}, \errval{EFAULT}.
@@ -2476,13 +3987,6 @@ ed impedirle restituendo un errore di \errcode{EDEADLK} alla funzione che
 cerca di acquisire un lock che porterebbe ad un \itindex{deadlock}
 \textit{deadlock}.
 
-\begin{figure}[!bht]
-  \centering \includegraphics[width=13cm]{img/file_posix_lock}
-  \caption{Schema dell'architettura del file locking, nel caso particolare  
-    del suo utilizzo secondo l'interfaccia standard POSIX.}
-  \label{fig:file_posix_lock}
-\end{figure}
-
 
 Per capire meglio il funzionamento del file locking in semantica POSIX (che
 differisce alquanto rispetto da quello di BSD, visto
@@ -2501,6 +4005,13 @@ questo caso la titolarit
 voce nella \itindex{file~table} \textit{file table}, ma con il valore del
 \acr{pid} del processo.
 
+\begin{figure}[!bht]
+  \centering \includegraphics[width=13cm]{img/file_posix_lock}
+  \caption{Schema dell'architettura del file locking, nel caso particolare  
+    del suo utilizzo secondo l'interfaccia standard POSIX.}
+  \label{fig:file_posix_lock}
+\end{figure}
+
 Quando si richiede un lock il kernel effettua una scansione di tutti i lock
 presenti sul file\footnote{scandisce cioè la \itindex{linked~list}
   \textit{linked list} delle strutture \struct{file\_lock}, scartando
@@ -2771,10 +4282,10 @@ che utilizza la funzione \funcd{lockf}, il cui prototipo 
   \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
     errore, nel qual caso \var{errno} assumerà uno dei valori:
     \begin{errlist}
-    \item[\errcode{EWOULDBLOCK}] Non è possibile acquisire il lock, e si è
+    \item[\errcode{EWOULDBLOCK}] non è possibile acquisire il lock, e si è
       selezionato \const{LOCK\_NB}, oppure l'operazione è proibita perché il
       file è mappato in memoria.
-    \item[\errcode{ENOLCK}] Il sistema non ha le risorse per il locking: ci
+    \item[\errcode{ENOLCK}] il sistema non ha le risorse per il locking: ci
       sono troppi segmenti di lock aperti, si è esaurita la tabella dei lock.
     \end{errlist}
     ed inoltre \errval{EBADF}, \errval{EINVAL}.
@@ -2796,7 +4307,7 @@ tab.~\ref{tab:file_lockf_type}.
     \const{LOCK\_SH}& Richiede uno \textit{shared lock}. Più processi possono
                       mantenere un lock condiviso sullo stesso file.\\
     \const{LOCK\_EX}& Richiede un \textit{exclusive lock}. Un solo processo
-                      alla volta può mantenere un lock esclusivo su un file. \\
+                      alla volta può mantenere un lock esclusivo su un file.\\
     \const{LOCK\_UN}& Sblocca il file.\\
     \const{LOCK\_NB}& Non blocca la funzione quando il lock non è disponibile,
                       si specifica sempre insieme ad una delle altre operazioni
@@ -2946,10 +4457,23 @@ possibilit
 % LocalWords:  flock shared exclusive operation dup inode linked NFS cmd ENOLCK
 % LocalWords:  EDEADLK whence SEEK CUR type pid GETLK SETLK SETLKW all'inode HP
 % LocalWords:  switch bsd lockf mandatory SVr sgid group root mount mand TRUNC
-% LocalWords:  SVID UX Documentation sendfile dnotify inotify NdA
+% LocalWords:  SVID UX Documentation sendfile dnotify inotify NdA ppoll fds add
+% LocalWords:  init EMFILE FIONREAD ioctl watch char pathname uint mask ENOSPC
+% LocalWords:  dell'inode CLOSE NOWRITE MOVE MOVED FROM TO rm wd event page ctl
+% LocalWords:  attribute Universe epoll Solaris kqueue level triggered Jonathan
+% LocalWords:  Lemon BSDCON edge Libenzi kevent backporting epfd EEXIST ENOENT
+% LocalWords:  MOD wait EPOLLIN EPOLLOUT EPOLLRDHUP SOCK EPOLLPRI EPOLLERR one
+% LocalWords:  EPOLLHUP EPOLLET EPOLLONESHOT shot maxevents ctlv ALL DONT HPUX
+% LocalWords:  FOLLOW ONESHOT ONLYDIR FreeBSD EIO caching sysctl instances name
+% LocalWords:  watches IGNORED ISDIR OVERFLOW overflow UNMOUNT queued cookie ls
+% LocalWords:  NUL sizeof casting printevent nread limits sysconf SC wrapper Di
+% LocalWords:  splice result argument DMA controller zerocopy Linus Larry Voy
+% LocalWords:  Jens Anxboe vmsplice seek ESPIPE GIFT TCP CORK MSG splicecp nr
+% LocalWords:  nwrite segs patch readahead posix fadvise TC advice FADV NORMAL
 
 
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"
 %%% End: 
+% LocalWords:  SEQUENTIAL NOREUSE WILLNEED DONTNEED streaming fallocate EFBIG