Aggiornamenti vari.
[gapil.git] / fileadv.tex
index a255851500e3df6f31b39457cfc58da36b883175..c3be626d21908e1b90ee2b69b2771e306f369b50 100644 (file)
@@ -940,7 +940,7 @@ I/O.
 
 Abbiamo visto in sez.~\ref{sec:sig_gen_beha}, affrontando la suddivisione fra
 \textit{fast} e \textit{slow} \textit{system call},\index{system~call~lente}
-che in certi casi le funzioni di I/O eseguite su un file descritor possono
+che in certi casi le funzioni di I/O eseguite su un file descriptor possono
 bloccarsi indefinitamente. Questo non avviene mai per i file normali, per i
 quali le funzioni di lettura e scrittura ritornano sempre subito, ma può
 avvenire per alcuni \index{file!di~dispositivo} file di dispositivo, come ad
@@ -1127,7 +1127,7 @@ funzione invece i \textit{file descriptor set} non vengono modificati anche in
 caso di errore.
 
 Si tenga presente infine che su Linux, in caso di programmazione
-\textit{multithread} se un file descriptor viene chiuso in un altro
+\textit{multi-thread} se un file descriptor viene chiuso in un altro
 \textit{thread} rispetto a quello in cui si sta usando \func{select}, questa
 non subisce nessun effetto. In altre varianti di sistemi unix-like invece
 \func{select} ritorna indicando che il file descriptor è pronto, con
@@ -1498,7 +1498,7 @@ questo comportamento non modificando mai il valore di \param{timeout} anche se
 in questo caso non esiste nessuno standard che richieda questo comportamento.
 
 Infine anche per \func{poll} e \func{ppoll} valgono le considerazioni relative
-alla possibilità di avere delle notificazione spurie della disponibilita di
+alla possibilità di avere delle notificazione spurie della disponibilità di
 accesso ai file descriptor illustrate per \func{select} in
 sez.~\ref{sec:file_select}, che non staremo a ripetere qui.
 
@@ -2762,8 +2762,8 @@ 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.
+lasciare tutto il resto a processi in \textit{user space}, non era stata
+prevista nessuna funzionalità di notifica.
 
 Visto però il crescente interesse nei confronti di una funzionalità di questo
 tipo, che è molto richiesta specialmente nello sviluppo dei programmi ad
@@ -3513,11 +3513,11 @@ dedicate per la lettura e la scrittura dei file, completamente separate
 rispetto a quelle usate normalmente.
 
 In generale questa interfaccia è completamente astratta e può essere
-implementata sia direttamente nel kernel che in user space attraverso l'uso di
-\itindex{thread} \textit{thread}. Per le versioni del kernel meno recenti
-esiste una implementazione di questa interfaccia fornita completamente delle
-\acr{glibc} a partire dalla versione 2.1, che è realizzata completamente in
-user space, ed è accessibile linkando i programmi con la libreria
+implementata sia direttamente nel kernel che in \textit{user space} attraverso
+l'uso di \itindex{thread} \textit{thread}. Per le versioni del kernel meno
+recenti esiste una implementazione di questa interfaccia fornita completamente
+delle \acr{glibc} a partire dalla versione 2.1, che è realizzata completamente
+in \textit{user space}, ed è accessibile linkando i programmi con la libreria
 \file{librt}. A partire dalla versione 2.5.32 è stato introdotto nel kernel
 una nuova infrastruttura per l'I/O asincrono, ma ancora il supporto è parziale
 ed insufficiente ad implementare tutto l'AIO POSIX.
@@ -4596,12 +4596,12 @@ L'indicazione viene espressa dall'argomento \param{advice} che deve essere
 specificato con uno dei valori riportati in
 tab.~\ref{tab:madvise_advice_values}; si tenga presente che i valori indicati
 nella seconda parte della tabella sono specifici di Linux e non sono previsti
-dallo standard POSIX.1b.
-La funzione non ha, tranne il caso di \const{MADV\_DONTFORK}, nessun effetto
-sul comportamento di un programma, ma può influenzarne le prestazioni fornendo
-al kernel indicazioni sulle esigenze dello stesso, così che sia possibile
-scegliere le opportune strategie per la gestione del \itindex{read-ahead}
-\textit{read-ahead} e del caching dei dati.
+dallo standard POSIX.1b.  La funzione non ha, tranne il caso di
+\const{MADV\_DONTFORK}, nessun effetto sul comportamento di un programma, ma
+può influenzarne le prestazioni fornendo al kernel indicazioni sulle esigenze
+dello stesso, così che sia possibile scegliere le opportune strategie per la
+gestione del \textit{read-ahead} (vedi sez.~\ref{sec:file_fadvise}) e del
+caching dei dati.
 
 \begin{table}[!htb]
   \centering
@@ -4734,10 +4734,10 @@ Nello standard POSIX.1-2001 è prevista una ulteriore funzione
 }
 \end{funcproto}
 
-Gli argomenti \param{addr} e \param{len} hanno lo stesso significato degli
-analoghi di \func{madvise}, mentre \param{advice} può assumere solo i valori
-indicati in tab.~\ref{tab:posix_madvise_advice_values}, che riflettono gli
-analoghi di \func{madvise}. 
+Gli argomenti \param{start} e \param{lenght} hanno lo stesso identico
+significato degli analoghi di \func{madvise}, a cui si rimanda per la loro
+descrizione ma a differenza di quanto indicato dallo standard per questa
+funzione, su Linux un valore nullo di \param{len} è consentito.
 
 \begin{table}[!htb]
   \centering
@@ -4758,8 +4758,11 @@ analoghi di \func{madvise}.
   \label{tab:posix_madvise_advice_values}
 \end{table}
 
-A differenza di quanto indicato dallo standard su Linux un valore nullo
-di \param{len} è consentito. Inoltre a partire dalle \acr{glibc} 2.6
+
+L'argomento \param{advice} invece può assumere solo i valori indicati in
+tab.~\ref{tab:posix_madvise_advice_values}, che riflettono gli analoghi di
+\func{madvise}, con lo stesso effetto per tutti tranne
+\const{POSIX\_MADV\_DONTNEED}.  Infatti a partire dalle \acr{glibc} 2.6
 \const{POSIX\_MADV\_DONTNEED} viene ignorato, in quanto l'uso del
 corrispondente \const{MADV\_DONTNEED} di \func{madvise} ha, per la semantica
 imperativa, l'effetto immediato di far liberare le pagine da parte del kernel,
@@ -4770,46 +4773,43 @@ che viene considerato distruttivo.
 \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 a \func{read} e \func{write}, ci sono casi in cui si vuole poter
-contare sulla atomicità delle operazioni.
+Una seconda modalità di I/O diversa da quella ordinaria è il cosiddetto
+\textsl{I/O vettorizzato}, che nasce per rispondere al caso abbastanza comune
+in cui ci si trova nell'esigenza di 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 a \func{read}
+e \func{write}, ci sono casi in cui si vuole poter contare sulla atomicità
+delle operazioni di lettura e scrittura rispetto all'esecuzione del programma.
 
 Per questo motivo fino da BSD 4.2 vennero introdotte delle nuove
 \textit{system call} che permettessero di effettuare con una sola chiamata una
-serie di letture o scritture su una serie di buffer, con quello che viene
-normalmente chiamato \textsl{I/O vettorizzato}. Queste funzioni sono
+serie di letture da, o scritture su, una serie di buffer, quello che poi venne
+chiamato \textsl{I/O vettorizzato}. Queste funzioni di sistema sono
 \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.} ed 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{funcproto}{
+\fhead{sys/uio.h}
+\fdecl{int readv(int fd, const struct iovec *vector, int count)}
+\fdecl{int writev(int fd, const struct iovec *vector, int count)}
+\fdesc{Eseguono rispettivamente una lettura o una scrittura vettorizzata.} 
+}
+
+{Le funzioni ritornano il numero di byte letti o scritti in caso di successo e
+  $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
   \begin{errlist}
-  \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
+    \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}
+  più tutti i valori, con lo stesso significato, che possono risultare
+  dalle condizioni di errore di \func{read} e \func{write}.
+ }
+\end{funcproto}
+
 
 Entrambe le funzioni usano una struttura \struct{iovec}, la cui definizione è
 riportata in fig.~\ref{fig:file_iovec}, che definisce dove i dati devono
@@ -4875,29 +4875,24 @@ sez.~\ref{sec:file_read} e \ref{sec:file_write}); le due funzioni sono
   bit dell'argomento \param{offset}, che varia a seconda delle architetture,
   ma queste differenze vengono gestite dalle funzioni di librerie di libreria
   che mantengono l'interfaccia delle analoghe tratte da BSD.}
-\begin{functions}
-  \headdecl{sys/uio.h}
-  
-  \funcdecl{int preadv(int fd, const struct iovec *vector, int count, off\_t
+
+
+\begin{funcproto}{
+\fhead{sys/uio.h}
+\fdecl{int preadv(int fd, const struct iovec *vector, int count, off\_t
     offset)}
-  \funcdecl{int pwritev(int fd, const struct iovec *vector, int count, off\_t
+\fdecl{int pwritev(int fd, const struct iovec *vector, int count, off\_t
     offset)}
+\fdesc{Eseguono una lettura o una scrittura vettorizzata a partire da una data
+  posizione sul file.} 
+}
 
-  Eseguono una lettura o una scrittura vettorizzata a partire da una data
-  posizione sul file.
-  
-  \bodydesc{Le funzioni hanno gli stessi valori di ritorno delle
-    corrispondenti \func{readv} e \func{writev}; anche gli eventuali errori
-    sono gli stessi già visti in precedenza, ma ad essi si possono aggiungere
-    per \var{errno} anche i valori:
-  \begin{errlist}
-  \item[\errcode{EOVERFLOW}] \param{offset} ha un valore che non può essere
-    usato come \type{off\_t}.
-  \item[\errcode{ESPIPE}] \param{fd} è associato ad un socket o una
-    \textit{pipe}.
-  \end{errlist}
+{ Le funzioni hanno gli stessi valori di ritorno delle corrispondenti
+  \func{readv} e \func{writev} ed anche gli eventuali errori sono gli stessi,
+  con in più quelli che si possono ottenere dalle possibili condizioni di
+  errore di \func{lseek}.
 }
-\end{functions}
+\end{funcproto}
 
 Le due funzioni eseguono rispettivamente una lettura o una scrittura
 vettorizzata a partire dalla posizione \param{offset} sul file indicato
@@ -4927,32 +4922,31 @@ 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.
+\textit{kernel space} a \textit{user space} e all'indietro, quando in realtà
+potrebbe essere più efficiente mantenere tutto in \textit{kernel
+  space}. Tratteremo in questa sezione alcune funzioni specialistiche che
+permettono di ottimizzare le prestazioni in questo tipo di situazioni.
 
 La prima funzione che è stata ideata per ottimizzare il trasferimento dei dati
-fra due file descriptor è \func{sendfile};\footnote{la funzione è stata
+fra due file descriptor è \func{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 prototipo
-di \funcd{sendfile} è:
-\begin{functions}  
-  \headdecl{sys/sendfile.h} 
+  2.1.} La funzione è presente in diverse versioni di Unix (la si ritrova ad
+esempio in FreeBSD, HPUX ed altri Unix) ma non è presente né in POSIX.1-2001
+né in altri standard (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 prototipo di \funcd{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}
+\begin{funcproto}{
+\fhead{sys/sendfile.h}
+\fdecl{ssize\_t sendfile(int out\_fd, int in\_fd, off\_t *offset, size\_t
+    count)}
+\fdesc{Copia dei dati da un file descriptor ad un altro.} 
+}
+
+{La funzione ritorna il numero di byte trasferiti in caso di successo e $-1$
+  per un 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
@@ -4961,17 +4955,16 @@ di \funcd{sendfile} è:
     \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}
+  \end{errlist}
+  ed inoltre \errcode{EBADF} e \errcode{EFAULT} nel loro significato
+  generico.}
+\end{funcproto}
 
 La funzione copia direttamente \param{count} byte dal file descriptor
-\param{in\_fd} al file descriptor \param{out\_fd}; in caso di successo
+\param{in\_fd} al file descriptor \param{out\_fd}. In caso di successo la
 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}.
+\param{out\_fd} e come per 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
@@ -4982,38 +4975,38 @@ 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
+Fino ai kernel della serie 2.4 la funzione era utilizzabile su un qualunque
+file descriptor, e permetteva 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.}
+sola chiamata a \funcd{sendfile}. In questo modo si poteva diminuire il numero
+di chiamate al sistema e risparmiare in trasferimenti di dati da
+\textit{kernel space} a \textit{user space} e viceversa.  La massima utilità
+della funzione si ottiene 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 (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
+In seguito però ci si accorse 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
+\func{write}. 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 \textit{user
+  space} che ha una conoscenza diretta su come questi sono strutturati, per
+cui 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 \url{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} da luogo ad un errore di \errcode{EINVAL}.
+casi l'uso di \func{sendfile} da luogo ad un errore di \errcode{EINVAL}.
 
 Nonostante ci possano essere casi in cui \func{sendfile} non migliora le
 prestazioni, resta il dubbio se la scelta di disabilitarla sempre per il
@@ -5021,27 +5014,31 @@ trasferimento fra file di dati sia davvero corretta. Se ci sono peggioramenti
 di prestazioni infatti si può sempre fare ricorso al metodo ordinario, ma
 lasciare a disposizione la funzione consentirebbe se non altro di semplificare
 la gestione della copia dei dati fra file, evitando di dover gestire
-l'allocazione di un buffer temporaneo per il loro trasferimento.
-
-Questo dubbio si può comunque ritenere superato con l'introduzione, avvenuta a
-partire dal kernel 2.6.17, della nuova \textit{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 \textit{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.}
+l'allocazione di un buffer temporaneo per il loro trasferimento. Comunque a
+partire dal kernel 2.6.33 la restrizione su \param{out\_fd} è stata rimossa e
+questo può essere un file qualunque, rimane però quella di non poter usare un
+socket per \param{in\_fd}.
+
+A partire dal kernel 2.6.17 come alternativa a \func{sendfile} è disponibile
+la nuova \textit{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}, 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 \textit{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'\textit{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 che
+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
@@ -5051,40 +5048,40 @@ Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
   dallo stesso Linus Torvalds in \url{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}''.
+gestito interamente in \textit{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 \textit{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 \textit{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
+destinazione dei dati che vengono letti da un file. La funzione fornisce
+quindi una interfaccia generica che consente di trasferire dati da un buffer
+ad un file o viceversa; il prototipo di \funcd{splice}, 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} 
 
-  \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 \textit{pipe} o viceversa.
+\begin{funcproto}{
+\fhead{fcntl.h} 
+\fdecl{long splice(int fd\_in, off\_t *off\_in, int fd\_out, off\_t
+    *off\_out, size\_t len, \\
+\phantom{long splice(}unsigned int flags)}
+\fdesc{Trasferisce dati da un file verso una \textit{pipe} o viceversa.} 
+}
 
-  \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}
+{La funzione ritorna il numero di byte trasferiti in caso di successo e $-1$
+  per un 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.
@@ -5098,18 +5095,19 @@ definito la macro \macro{\_GNU\_SOURCE},\footnote{si ricordi che questa
       richiesta.
     \item[\errcode{ESPIPE}] o \param{off\_in} o \param{off\_out} non sono
       \val{NULL} ma il corrispondente file descriptor è una \textit{pipe}.
-    \end{errlist}
-  }
-\end{functions}
+  \end{errlist}
+}
+\end{funcproto}
+
 
 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. 
+una \textit{pipe}; l'altro file descriptor può essere qualunque, 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 \textit{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
@@ -5151,8 +5149,15 @@ descrizioni complete di tutti i valori possibili anche quando, come per
     \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}.\\ 
+                                 copiarle: 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 \textit{pipe} o
+                                 il buffer non corrisponda a pagine intere
+                                 esse saranno comunque copiate. 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
@@ -5166,13 +5171,24 @@ descrizioni complete di tutti i valori possibili anche quando, come per
                                  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
+                                 socket. 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}).  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
+                                 ``\textsl{donate}'' al kernel; 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. 
+                                 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
@@ -5188,50 +5204,30 @@ descrizioni complete di tutti i valori possibili anche quando, come per
   \label{tab:splice_flag}
 \end{table}
 
-\footnotetext[120]{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 \textit{pipe} o il buffer non corrisponda a pagine
-  intere esse saranno comunque copiate.}
-
-\footnotetext[121]{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}. 
+su un altro senza utilizzare buffer in \textit{user space}. Lo scopo del
+programma è quello di eseguire la copia dei dati con \func{splice}, questo
+significa che si dovrà usare la funzione due volte, prima per leggere i dati
+dal file di ingresso e poi per scriverli su quello di uscita, appoggiandosi 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}
+  \includegraphics[height=3.5cm]{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.
+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, le funzioni di ausilio, le
+aperture dei file di ingresso e di uscita passati come argomenti e quella
+della \textit{pipe} intermedia, è riportato in fig.~\ref{fig:splice_example}.
 
-\begin{figure}[!htbp]
+\begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{\codesamplewidth}
     \includecodesample{listati/splicecp.c}
@@ -5242,29 +5238,30 @@ infine (\texttt{\small 28-31}) la \textit{pipe} che verrà usata come buffer.
   \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
+Il ciclo principale (\texttt{\small 13-38}) inizia con la lettura dal file
+sorgente tramite la prima \func{splice} (\texttt{\small 14-15}), 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
+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).
+semplicemente al trasferimento dei dati dal file al buffer in \textit{kernel
+  space}.
 
 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
+detto valore è nullo (\texttt{\small 16}) 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
+  59}). In caso di valore negativo (\texttt{\small 17-24}) c'è stato un
+errore ed allora si ripete la lettura (\texttt{\small 16}) se questo è dovuto
 ad una interruzione, o altrimenti si esce con un messaggio di errore
-(\texttt{\small 41-43}).
+(\texttt{\small 21-23}).
 
 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
+(\texttt{\small 25-37}); questo inizia (\texttt{\small 26-27}) 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
@@ -5274,8 +5271,8 @@ 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
+(\texttt{\small 28-35}). Infine si chiude il ciclo di scrittura sottraendo
+(\texttt{\small 37}) 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
@@ -5285,49 +5282,47 @@ 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.
+al posto della seconda, utilizzando un buffer in \textit{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 \textit{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 anche
 altre due \textit{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
+trasferimento di dati attraverso un buffer in \textit{kernel space}; benché
+queste non attengono strettamente ad operazioni di trasferimento dati fra file
 descriptor, le tratteremo qui, essendo strettamente correlate fra loro.
 
 La prima funzione, \funcd{vmsplice}, è la più simile a \func{splice} e come
 indica il suo nome consente di trasferire i dati dalla memoria virtuale di un
 processo (ad esempio per un file mappato in memoria) 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}.
+\begin{funcproto}{
+\fhead{fcntl.h} 
+\fhead{sys/uio.h}
+\fdecl{long vmsplice(int fd, const struct iovec *iov, unsigned long nr\_segs,\\
+\phantom{long vmsplice(}unsigned int flags)}
+\fdesc{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}
+{La funzione ritorna il numero di byte trasferiti in caso di successo e $-1$
+  per un 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}
+  \end{errlist}
+}
+\end{funcproto}
 
 La \textit{pipe} indicata da \param{fd} dovrà essere specificata tramite il
 file descriptor corrispondente al suo capo aperto in scrittura (di nuovo si
@@ -5352,31 +5347,31 @@ 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} 
+suo nome all'omonimo comando in \textit{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 \textit{kernel space}, la funzione consente di
+eseguire una copia del contenuto del buffer stesso. Il prototipo di
+\funcd{tee} è il seguente:
 
-  \funcdecl{long tee(int fd\_in, int fd\_out, size\_t len, unsigned int
+\begin{funcproto}{
+\fhead{fcntl.h}
+\fdecl{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.
+\fdesc{Duplica i dati 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}
+{La funzione ritorna restituisce il numero di byte copiati in caso di successo
+  e $-1$ per un 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}
+  \end{errlist}
+}
+\end{funcproto}
 
 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}
@@ -5394,17 +5389,17 @@ funzione non bloccante.
 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 \textit{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
+stato chiuso; 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.
+dello \textit{standard input} sullo \textit{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]
+\begin{figure}[!htb]
   \footnotesize \centering
   \begin{minipage}[c]{\codesamplewidth}
     \includecodesample{listati/tee.c}
@@ -5415,28 +5410,27 @@ allegati alla guida.
   \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}.
+La prima parte del programma, che si è omessa per brevità, si cura
+semplicemente di controllare che sia stato fornito almeno un argomento (il
+nome del file su cui scrivere), di aprirlo e che sia lo standard input che lo
+standard output corrispondano ad una \textit{pipe}.
 
-Il ciclo principale (\texttt{\small 37-58}) inizia con la chiamata a
+Il ciclo principale (\texttt{\small 11-32}) 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
+(\texttt{\small 13}), 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
+non ci sono più dati da leggere e si chiude il ciclo (\texttt{\small 14}), 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
+dovuto ad una interruzione (\texttt{\small 15-48}) o si stampa un messaggio
+di errore e si esce negli altri casi (\texttt{\small 18-21}).
+
+Una volta completata la copia dei dati sullo \textit{standard output} si
+possono estrarre dallo \textit{standard input} e scrivere sul file, di nuovo
+su usa un ciclo di scrittura (\texttt{\small 24-31}) in cui si ripete una
+chiamata a \func{splice} (\texttt{\small 25}) 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}:
@@ -5477,29 +5471,29 @@ il loro accesso ai dati dei file e controllare la gestione del relativo
 \itindbeg{read-ahead}
 
 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}
+ordinaria dell'I/O su un file è \funcd{readahead} (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 è:
 
-  \funcdecl{ssize\_t readahead(int fd, off64\_t *offset, size\_t count)}
-  
-  Esegue una lettura preventiva del contenuto di un file in cache.
+\begin{funcproto}{
+\fhead{fcntl.h}
+\fdecl{ssize\_t readahead(int fd, off64\_t *offset, size\_t count)}
+\fdesc{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}
+{La funzione ritorna $0$ in caso di successo e $-1$ per un 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 \textit{pipe} o un socket).
-    \end{errlist}
-  }
-\end{functions}
+  \end{errlist}
+}
+\end{funcproto}
 
 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
@@ -5508,7 +5502,7 @@ virtuale ed il meccanismo della 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} vengono arrotondati di conseguenza.
 
-La funzione estende quello che è un comportamento normale del kernel che
+La funzione estende quello che è un comportamento normale del kernel che,
 quando si legge un file, aspettandosi che l'accesso prosegua, esegue sempre
 una lettura preventiva di una certa quantità di dati; questo meccanismo di
 lettura anticipata viene chiamato \textit{read-ahead}, da cui deriva il nome
@@ -5528,35 +5522,38 @@ nelle operazioni successive.
 \itindend{read-ahead}
 
 Il concetto di \func{readahead} viene generalizzato nello standard
-POSIX.1-2001 dalla funzione \func{posix\_fadvise},\footnote{anche se
-  l'argomento \param{len} è stato modificato da \type{size\_t} a \type{off\_t}
-  nella revisione POSIX.1-2003 TC5.} che consente di ``\textsl{avvisare}'' il
+POSIX.1-2001 dalla funzione \func{posix\_fadvise} (anche se
+l'argomento \param{len} è stato modificato da \type{size\_t} a \type{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 prototipo di \funcd{posix\_fadvise}, che è
-disponibile soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad
-valore di almeno 600, è:
-\begin{functions}  
-  \headdecl{fcntl.h} 
+porzione di un file, così che esso possa provvedere le opportune
+ottimizzazioni; il prototipo di \funcd{posix\_fadvise}\footnote{la funzione è
+  stata introdotta su Linux solo a partire dal kernel 2.5.60, ed è disponibile
+  soltanto se è stata definita la macro \macro{\_XOPEN\_SOURCE} ad valore di
+  almeno \texttt{600} o la macro \macro{\_POSIX\_C\_SOURCE} ad valore di
+  almeno \texttt{200112L}.} è:
 
-  \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}
+\begin{funcproto}{
+\fhead{fcntl.h}
+\fdecl{int posix\_fadvise(int fd, off\_t offset, off\_t len, int advice)}
+\fdesc{Dichiara al kernel le future modalità di accesso ad un file.}
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un 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 \textit{pipe} o un socket).
-    \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una \textit{pipe} o
-      un socket (ma su Linux viene restituito \errcode{EINVAL}).
-    \end{errlist}
-  }
-\end{functions}
+    \item[\errcode{ESPIPE}] previsto dallo standard se \param{fd} è una
+      \textit{pipe} o un socket (ma su Linux viene restituito
+      \errcode{EINVAL}).
+  \end{errlist}
+}
+\end{funcproto}
 
 La funzione dichiara al kernel le modalità con cui intende accedere alla
 regione del file indicato da \param{fd} che inizia alla posizione
@@ -5827,10 +5824,11 @@ livello di kernel.
 % LocalWords:  clockid CLOCK MONOTONIC REALTIME itimerspec interval Resource
 % LocalWords:  ABSTIME gettime temporarily unavailable SIGINT SIGQUIT SIGTERM
 % LocalWords:  sigfd fifofd break siginf names starting echo Message from Got
-% LocalWords:  message kill received means exit
+% LocalWords:  message kill received means exit TLOCK ULOCK EPOLLWAKEUP
 
 
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"
 %%% End: 
+