+
+\subsection{I/O vettorizzato: \func{readv} e \func{writev}}
+\label{sec:file_multiple_io}
+
+Un caso abbastanza comune è quello in cui ci si trova a dover eseguire una
+serie multipla di operazioni di I/O, come una serie di letture o scritture di
+vari buffer. Un esempio tipico è quando i dati sono strutturati nei campi di
+una struttura ed essi devono essere caricati o salvati su un file. Benché
+l'operazione sia facilmente eseguibile attraverso una serie multipla di
+chiamate, ci sono casi in cui si vuole poter contare sulla atomicità delle
+operazioni.
+
+Per questo motivo su BSD 4.2 sono state introdotte due nuove system call,
+\funcd{readv} e \funcd{writev},\footnote{in Linux le due funzioni sono riprese
+ da BSD4.4, esse sono previste anche dallo standard POSIX.1-2001.} che
+permettono di effettuare con una sola chiamata una lettura o una scrittura su
+una serie di buffer (quello che viene chiamato \textsl{I/O vettorizzato}. I
+relativi prototipi sono:
+\begin{functions}
+ \headdecl{sys/uio.h}
+
+ \funcdecl{int readv(int fd, const struct iovec *vector, int count)}
+ \funcdecl{int writev(int fd, const struct iovec *vector, int count)}
+
+ Eseguono rispettivamente una lettura o una scrittura vettorizzata.
+
+ \bodydesc{Le funzioni restituiscono il numero di byte letti o scritti in
+ caso di successo, e -1 in caso di errore, nel qual caso \var{errno}
+ assumerà uno dei valori:
+ \begin{errlist}
+ \item[\errcode{EINVAL}] si è specificato un valore non valido per uno degli
+ argomenti (ad esempio \param{count} è maggiore di \const{IOV\_MAX}).
+ \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale prima di
+ di avere eseguito una qualunque lettura o scrittura.
+ \item[\errcode{EAGAIN}] \param{fd} è stato aperto in modalità non bloccante e
+ non ci sono dati in lettura.
+ \item[\errcode{EOPNOTSUPP}] la coda delle richieste è momentaneamente piena.
+ \end{errlist}
+ ed anche \errval{EISDIR}, \errval{EBADF}, \errval{ENOMEM}, \errval{EFAULT}
+ (se non sono stati allocati correttamente i buffer specificati nei campi
+ \var{iov\_base}), più gli eventuali errori delle funzioni di lettura e
+ scrittura eseguite su \param{fd}.}
+\end{functions}
+
+Entrambe le funzioni usano una struttura \struct{iovec}, la cui definizione è
+riportata in fig.~\ref{fig:file_iovec}, che definisce dove i dati devono
+essere letti o scritti ed in che quantità. Il primo campo della struttura,
+\var{iov\_base}, contiene l'indirizzo del buffer ed il secondo,
+\var{iov\_len}, la dimensione dello stesso.
+
+\begin{figure}[!htb]
+ \footnotesize \centering
+ \begin{minipage}[c]{15cm}
+ \includestruct{listati/iovec.h}
+ \end{minipage}
+ \normalsize
+ \caption{La struttura \structd{iovec}, usata dalle operazioni di I/O
+ vettorizzato.}
+ \label{fig:file_iovec}
+\end{figure}
+
+La lista dei buffer da utilizzare viene indicata attraverso l'argomento
+\param{vector} che è un vettore di strutture \struct{iovec}, la cui lunghezza
+è specificata dall'argomento \param{count}.\footnote{fino alle libc5, Linux
+ usava \type{size\_t} come tipo dell'argomento \param{count}, una scelta
+ logica, che però è stata dismessa per restare aderenti allo standard
+ POSIX.1-2001.} Ciascuna struttura dovrà essere inizializzata opportunamente
+per indicare i vari buffer da e verso i quali verrà eseguito il trasferimento
+dei dati. Essi verranno letti (o scritti) nell'ordine in cui li si sono
+specificati nel vettore \param{vector}.
+
+La standardizzazione delle due funzioni all'interno della revisione
+POSIX.1-2001 prevede anche che sia possibile avere un limite al numero di
+elementi del vettore \param{vector}. Qualora questo sussista, esso deve essere
+indicato dal valore dalla costante \const{IOV\_MAX}, definita come le altre
+costanti analoghe (vedi sez.~\ref{sec:sys_limits}) in \file{limits.h}; lo
+stesso valore deve essere ottenibile in esecuzione tramite la funzione
+\func{sysconf} richiedendo l'argomento \const{\_SC\_IOV\_MAX} (vedi
+sez.~\ref{sec:sys_sysconf}).
+
+Nel caso di Linux il limite di sistema è di 1024, però se si usano le
+\acr{glibc} queste forniscono un \textit{wrapper} per le system call che si
+accorge se una operazione supererà il precedente limite, in tal caso i dati
+verranno letti o scritti con le usuali \func{read} e \func{write} usando un
+buffer di dimensioni sufficienti appositamente allocato e sufficiente a
+contenere tutti i dati indicati da \param{vector}. L'operazione avrà successo
+ma si perderà l'atomicità del trasferimento da e verso la destinazione finale.
+
+% TODO verificare cosa succederà a preadv e pwritev o alla nuova niovec
+% vedi http://lwn.net/Articles/164887/
+
+
+\subsection{L'I/O diretto fra file descriptor: \func{sendfile} e \func{splice}}
+\label{sec:file_sendfile_splice}
+
+Uno dei problemi che si presentano nella gestione dell'I/O è quello in cui si
+devono trasferire grandi quantità di dati da un file descriptor ed un altro;
+questo usualmente comporta la lettura dei dati dal primo file descriptor in un
+buffer in memoria, da cui essi vengono poi scritti sul secondo.
+
+Benché il kernel ottimizzi la gestione di questo processo quando si ha a che
+fare con file normali, in generale quando i dati da trasferire sono molti si
+pone il problema di effettuare trasferimenti di grandi quantità di dati da
+kernel space a user space e all'indietro, quando in realtà potrebbe essere più
+efficiente mantenere tutto in kernel space. Tratteremo in questa sezione
+alcune funzioni specialistiche che permettono di ottimizzare le prestazioni in
+questo tipo di situazioni.
+
+La prima funzione che si pone l'obiettivo di ottimizzare il trasferimento dei
+dati fra due file descriptor è \funcd{sendfile};\footnote{la funzione è stata
+ introdotta con i kernel della serie 2.2, e disponibile dalle \acr{glibc}
+ 2.1..} la funzione è presente in diverse versioni di Unix,\footnote{la si
+ ritrova ad esempio in FreeBSD, HPUX ed altri Unix.} ma non è presente né in
+POSIX.1-2001 né in altri standard,\footnote{pertanto si eviti di utilizzarla
+ se si devono scrivere programmi portabili.} per cui per essa vengono
+utilizzati prototipi e semantiche differenti; nel caso di Linux il suo
+prototipo è:
+\begin{functions}
+ \headdecl{sys/sendfile.h}
+
+ \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} ed 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 socket di rete,\footnote{il
+ caso classico del lavoro 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.}
+
+Con i kernel della serie 2.6 ci si è accorti però che, a parte quest'ultimo
+caso, l'uso di \func{sendfile} non sempre portava significativi miglioramenti
+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
+ maggiore conoscenza su come questi sono strutturati.} e che anzi in certi
+casi si avevano dei peggioramenti, questo ha portato alla
+decisione\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}
+ {\texttt{http://www.cs.helsinki.fi/linux/linux-kernel/2001-03/0200.html}}.}
+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 si avrà
+un errore di \errcode{EINVAL}.
+
+Nonostante i limiti illustrati resta comunque il dubbio se la scelta di
+disabilitare \func{sendfile} per il trasferimento di dati fra file di dati sia
+davvero corretta; la funzione infatti se non altro consentirebbe di
+semplificare l'interfaccia per la copia dei dati, evitando di dover gestire
+l'allocazione di un buffer temporaneo per il loro trasferimento in tutti quei
+casi in cui non c'è necessità di fare controlli sugli stessi. Inoltre essa
+avrebbe comunque il vantaggio di evitare trasferimenti di dati da e verso
+l'user space.
+
+Il dubbio è stato rimosso con l'introduzione della system call
+\func{splice},\footnote{avvenuto a partire dal kernel 2.6.17.} il cui scopo è
+appunto quello di fornire un meccanismo generico per il trasferimento di dati
+da o verso un file utilizzando un buffer intermedio gestito direttamente dal
+kernel. Lo scopo della funzione può sembrare lo stesso di \func{sendfile}, ma
+in realtà esse sono profondamente diverse nel loro meccanismo di
+funzionamento; \func{sendfile} infatti, come accennato, non necessita affatto
+(anzi nel caso di Linux viene sostanzialmente usata solo in questo caso) di
+avere a disposizione un buffer interno, perché esegue un trasferimento diretto
+di dati; questo la rende in generale molto più efficiente, ma anche limitata
+nelle sue applicazioni.
+
+Il concetto che sta dietro a \func{splice} invece è diverso,\footnote{in
+ realtà la proposta originale di Larry Mc Voy non ne differisce poi tanto,
+ quello che la rende davvero diversa è stata la reinterpretazione che ne è
+ stata fatta nell'implementazione su Linux realizzata da Jens Anxboe, di cui
+ si può trovare un buon riassunto in \href{http://kerneltrap.org/node/6505}
+ {\texttt{http://kerneltrap.org/node/6505}}.} si tratta semplicemente di una
+funzione che consente di fare delle operazioni di trasferimento dati da e
+verso un buffer interamente gestito in kernel space, in maniera del tutto
+generica. In questo caso il cuore della funzione (e delle affini
+\func{vmsplice} e \func{tee}, che tratteremo più avanti) è appunto il buffer
+in kernel space; questo è anche quello che ne ha semplificato
+l'adozione,\footnote{la funzione infatti non è definita in nessuno standard,
+ e, allo stato attuale è disponibile soltanto su Linux.} perché
+l'infrastruttura per la gestione di un buffer in kernel space è presente fin
+dagli albori di Unix per la realizzazione delle \textit{pipe} (tratteremo
+l'argomento in sez.~\ref{sec:ipc_unix}). Dal punto di vista concettuale allora
+\func{splice} non è che un'altra interfaccia con cui esporre in userspace
+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 dove appoggiare i dati che vengono trasferiti da un capo
+all'altro della stessa (vedi fig.~\ref{fig:ipc_pipe_singular}) per creare un
+meccanismo di comunicazione fra processi, nel caso di \funcd{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 infatti è una
+interfaccia generica che consente di trasferire dati da un buffer ad un file o
+viceversa; il suo prototipo, accessibile solo avendo definito
+\macro{\_GNU\_SOURCE},\footnote{ovviamente, essendo come detto la funzione
+ totalmente specifica di Linux, essa non è prevista da nessuno standard e
+ deve essere evitata se si vogliono scrivere programmi portabili.} è:
+\begin{functions}
+ \headdecl{fcntl.h}
+
+ \funcdecl{}
+
+ 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{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}
+
+
+
+% TODO documentare le funzioni tee e splice
+% http://kerneltrap.org/node/6505 e http://lwn.net/Articles/178199/ e
+% http://lwn.net/Articles/179492/
+% e http://en.wikipedia.org/wiki/Splice_(system_call)
+
+
+
+
+\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.
+
+
+% TODO documentare \func{madvise}
+% TODO documentare \func{mincore}
+% TODO documentare \func{posix\_fadvise}
+% vedi http://insights.oetiker.ch/linux/fadvise.html
+% questo tread? http://www.ussg.iu.edu/hypermail/linux/kernel/0703.1/0032.html
+
+% TODO documentare \func{fallocate}, introdotta con il 2.6.23
+% vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/