+\footnotetext{se usato su altri tipi di filesystem causa un errore di
+ \errcode{ENOSYS}.}
+
+\footnotetext{a partire dal kernel 2.6.32 è stato introdotto un meccanismo che
+ identifica pagine di memoria identiche e le accorpa in una unica pagina
+ (soggetta al \textit{copy-on-write} per successive modifiche); per evitare
+ di controllare tutte le pagine solo quelle marcate con questo flag vengono
+ prese in considerazione per l'accorpamento; in questo modo si possono
+ migliorare le prestazioni nella gestione delle macchine virtuali diminuendo
+ la loro occupazione di memoria, ma il meccanismo può essere usato anche in
+ altre applicazioni in cui sian presenti numerosi processi che usano gli
+ stessi dati; per maggiori dettagli si veda
+ \href{http://kernelnewbies.org/Linux_2_6_32\#head-d3f32e41df508090810388a57efce73f52660ccb}{\texttt{http://kernelnewbies.org/Linux\_2\_6\_32}}.}
+
+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. A differenza da quanto specificato
+nello standard POSIX.1b, per il quale l'uso di \func{madvise} è a scopo
+puramente indicativo, Linux considera queste richieste come imperative, per
+cui ritorna un errore qualora non possa soddisfarle.\footnote{questo
+ comportamento differisce da quanto specificato nello standard.}
+
+\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 a \func{read} e \func{write}, ci sono casi in cui si vuole poter
+contare sulla atomicità delle operazioni.
+
+Per questo motivo fino da BSD 4.2 vennero introdotte delle nuove 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 \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{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]{\textwidth}
+ \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.
+
+Si tenga presente infine che queste funzioni operano sui file con
+l'interfaccia dei file descriptor, e non è consigliabile mescolarle con
+l'interfaccia classica dei \textit{file stream} di
+cap.~\ref{cha:files_std_interface}; a causa delle bufferizzazioni interne di
+quest'ultima infatti si potrebbero avere risultati indefiniti e non
+corrispondenti a quanto aspettato.
+
+Come per le normali operazioni di lettura e scrittura, anche per l'\textsl{I/O
+ vettorizzato} si pone il problema di poter effettuare le operazioni in
+maniera atomica a partire da un certa posizione sul file. Per questo motivo a
+partire dal kernel 2.6.30 sono state introdotte anche per l'\textsl{I/O
+ vettorizzato} le analoghe delle funzioni \func{pread} e \func{pwrite} (vedi
+sez.~\ref{sec:file_read} e \ref{sec:file_write}); le due funzioni sono
+\funcd{preadv} e \func{pwritev} ed i rispettivi prototipi sono:\footnote{le
+ due funzioni sono analoghe alle omonime presenti in BSD; le \textit{system
+ call} usate da Linux (introdotte a partire dalla versione 2.6.30)
+ utilizzano degli argomenti diversi per problemi collegati al formato a 64
+ 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
+ offset)}
+ \funcdecl{int pwritev(int fd, const struct iovec *vector, int count, off\_t
+ offset)}
+
+ 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 pipe.
+ \end{errlist}
+}
+\end{functions}
+
+Le due funzioni eseguono rispettivamente una lettura o una scrittura
+vettorizzata a partire dalla posizione \param{offset} sul file indicato
+da \param{fd}, la posizione corrente sul file, come vista da eventuali altri
+processi che vi facciano riferimento, non viene alterata. A parte la presenza
+dell'ulteriore argomento il comportamento delle funzioni è identico alle
+precedenti \func{readv} e \func{writev}.
+
+Con l'uso di queste funzioni si possono evitare eventuali
+\itindex{race~condition} \textit{race condition} quando si deve eseguire la
+una operazione di lettura e scrittura vettorizzata a partire da una certa
+posizione su un file, mentre al contempo si possono avere in concorrenza
+processi che utilizzano lo stesso file descriptor (si ricordi quanto visto in
+sez.~\ref{sec:file_adv_func}) con delle chiamate a \func{lseek}.
+
+
+
+\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 è stata ideata per ottimizzare il trasferimento dei dati
+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}
+
+ \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}
+
+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, resta il dubbio se la scelta di disabilitarla sempre per il
+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 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}
+
+ \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.
+
+ \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
+ \val{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}
+
+\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 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}.
+
+\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}[!htbp]
+ \footnotesize \centering
+ \begin{minipage}[c]{\codesamplewidth}
+ \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 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
+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}.
+
+ \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} indicata da \param{fd} 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
+segmenti della memoria del processo devono essere trasferiti verso di essa si
+dovrà utilizzare un vettore di strutture \struct{iovec} (vedi
+fig.~\ref{fig:file_iovec}), esattamente con gli stessi criteri con cui le si
+usano per l'I/O vettorizzato, indicando gli indirizzi e le dimensioni di
+ciascun segmento di memoria su cui si vuole operare; 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
+\textit{pipe}. In generale, se i dati una volta creati non devono essere
+riutilizzati (se cioè l'applicazione che chiama \func{vmsplice} non
+modificherà più la memoria trasferita), è opportuno utilizzare
+per \param{flag} il valore \const{SPLICE\_F\_GIFT}; questo fa sì che il kernel
+possa rimuovere le relative pagine dalla cache della memoria virtuale, 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}). Al
+momento\footnote{quello della stesura di questo paragrafo, avvenuta il Gennaio
+ 2010, in futuro potrebbe essere implementato anche \const{SPLICE\_F\_MORE}.}
+il solo valore utilizzabile per \param{flag}, fra quelli elencati in
+tab.~\ref{tab:splice_flag}, è \const{SPLICE\_F\_NONBLOCK} che rende la
+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 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]{\codesamplewidth}
+ \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.
+
+% TODO?? dal 2.6.25 splice ha ottenuto il supporto per la ricezione su rete
+
+
+\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}.
+
+\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}
+
+ \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} vengono arrotondati di conseguenza.
+
+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
+della funzione. La funzione \func{readahead}, per ottimizzare gli accessi a
+disco, effettua la lettura in cache della sezione richiesta e si blocca
+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 di un programma tutte le volte che si conosce in anticipo quanti
+dati saranno necessari nelle elaborazioni successive. Si potrà così
+concentrare in un unico momento (ad esempio in fase di inizializzazione) la
+lettura dei dati da disco, così da ottenere una migliore velocità di risposta
+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
+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}
+
+ \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}, che riprendono il significato
+degli analoghi già visti in sez.~\ref{sec:file_memory_map} per
+\func{madvise}.\footnote{dato che si tratta dello stesso tipo di funzionalità,
+ in questo caso applicata direttamente al sistema ai contenuti di un file
+ invece che alla sua mappatura in memoria.} 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 delle costanti usabili per l'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}