+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 \headfile{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_limits}).
+
+Nel caso di Linux il limite di sistema è di 1024, però se si usano le
+\acr{glibc} queste forniscono un \textit{wrapper} per le \textit{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
+sez.~\ref{sec: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 \funcd{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{funcproto}{
+\fhead{sys/uio.h}
+\fdecl{int preadv(int fd, const struct iovec *vector, int count, off\_t
+ offset)}
+\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.}
+}
+
+{ 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{funcproto}
+
+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 \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}.
+
+% TODO trattare preadv2() e pwritev2(), introdotte con il kernel 4.6, vedi
+% http://lwn.net/Articles/670231/ ed il flag RWF_HIPRI
+
+
+\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
+\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
+ introdotta con i kernel della serie 2.2, e disponibile dalle \acr{glibc}
+ 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} è:
+
+
+\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
+ (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} 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 la
+funzione ritorna il numero di byte effettivamente copiati da \param{in\_fd} a
+\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
+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 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 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 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}. 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}.
+
+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. 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
+ 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 \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 \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 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{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.}
+}
+
+{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.
+ \item[\errcode{EINVAL}] il filesystem su cui si opera non supporta
+ \func{splice}, oppure nessuno dei file descriptor è una \textit{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{lseek}.
+ \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{funcproto}