Modifiche del kernel 4.3
[gapil.git] / fileadv.tex
index b376483c6c301882c1bb1698522287ff365fa29e..688fab8da124d145e7cfe801500da2848ac30366 100644 (file)
-\chapter{La gestione avanzata dei file}
-\label{cha:file_advanced}
+capacità \const{CAP\_LEASE}, vedi sez.~\ref{sec:proc_capabilities}) può
+acquisire \textit{lease} su qualunque file.
 
-In questo capitolo affronteremo le tematiche relative alla gestione avanzata
-dei file, che non sono state trattate in \capref{cha:file_unix_interface},
-dove ci si è limitati ad una panoramica delle funzioni base. In particolare
-tratteremo delle funzioni di input/output avanzato e del \textit{file
-  locking}.
+Se su un file è presente un \textit{lease} quando il \textit{lease breaker}
+esegue una \func{truncate} o una \func{open} che confligge con
+esso,\footnote{in realtà \func{truncate} confligge sempre, mentre \func{open},
+  se eseguita in sola lettura, non confligge se si tratta di un \textit{read
+    lease}.} la funzione si blocca (a meno di non avere aperto il file con
+\const{O\_NONBLOCK}, nel qual caso \func{open} fallirebbe con un errore di
+\errcode{EWOULDBLOCK}) e viene eseguita la notifica al \textit{lease holder},
+così che questo possa completare le sue operazioni sul file e rilasciare il
+\textit{lease}.  In sostanza con un \textit{read lease} si rilevano i
+tentativi di accedere al file per modificarne i dati da parte di un altro
+processo, mentre con un \textit{write lease} si rilevano anche i tentativi di
+accesso in lettura.  Si noti comunque che le operazioni di notifica avvengono
+solo in fase di apertura del file e non sulle singole operazioni di lettura e
+scrittura.
 
+L'utilizzo dei \textit{file lease} consente al \textit{lease holder} di
+assicurare la consistenza di un file, a seconda dei due casi, prima che un
+altro processo inizi con le sue operazioni di scrittura o di lettura su di
+esso. In genere un \textit{lease holder} che riceve una notifica deve
+provvedere a completare le necessarie operazioni (ad esempio scaricare
+eventuali buffer), per poi rilasciare il \textit{lease} così che il
+\textit{lease breaker} possa eseguire le sue operazioni. Questo si fa con il
+comando \const{F\_SETLEASE}, o rimuovendo il \textit{lease} con
+\const{F\_UNLCK}, o, nel caso di \textit{write lease} che confligge con una
+operazione di lettura, declassando il \textit{lease} a lettura con
+\const{F\_RDLCK}.
 
-\section{Le funzioni di I/O avanzato}
-\label{sec:file_advanced_io}
+Se il \textit{lease holder} non provvede a rilasciare il \textit{lease} entro
+il numero di secondi specificato dal parametro di sistema mantenuto in
+\sysctlfile{fs/lease-break-time} sarà il kernel stesso a rimuoverlo o
+declassarlo automaticamente (questa è una misura di sicurezza per evitare che
+un processo blocchi indefinitamente l'accesso ad un file acquisendo un
+\textit{lease}). Una volta che un \textit{lease} è stato rilasciato o
+declassato (che questo sia fatto dal \textit{lease holder} o dal kernel è lo
+stesso) le chiamate a \func{open} o \func{truncate} eseguite dal \textit{lease
+  breaker} rimaste bloccate proseguono automaticamente.
 
-In questa sezione esamineremo le funzioni che permettono una gestione più
-sofisticata dell'I/O su file, a partire da quelle che permettono di gestire
-l'accesso contemporaneo a più file, per concludere con la gestione dell'I/O
-mappato in memoria.
-
-
-\subsection{La modalità di I/O \textsl{non-bloccante}}
-\label{sec:file_noblocking}
-
-Abbiamo visto in \secref{sec:sig_gen_beha}, affrontando la suddivisione fra
-\textit{fast} e \textit{slow} system call, che in certi casi le funzioni di
-I/O possono bloccarsi indefinitamente.\footnote{si ricordi però che questo può
-  accadere solo per le pipe, i socket ed alcuni file di dispositivo; sui file
-  normali le funzioni di lettura e scrittura ritornano sempre subito.}  Ad
-esempio le operazioni di lettura possono bloccarsi quando non ci sono dati
-disponibili sul descrittore su cui si sta operando.
-
-Questo comportamento causa uno dei problemi più comuni che ci si trova ad
-affrontare nelle operazioni di I/O, che è quello che si verifica quando si
-devono eseguire operazioni che possono bloccarsi su più file descriptor:
-mentre si è bloccati su uno di questi file su di un'altro potrebbero essere
-presenti dei dati, così che nel migliore dei casi si avrebbe una lettura
-ritardata inutilmente, e nel peggiore si potrebbe addirittura arrivare ad un
-deadlock.
-
-Abbiamo già accennato in \secref{sec:file_open} che però è possibile prevenire
-questo tipo di comportamento aprendo un file in modalità
-\textsl{non-bloccante}, attraverso l'uso del flag \macro{O\_NONBLOCK} nella
-chiamata di \func{open}. In questo caso le funzioni di input/output che
-altrimenti si sarebbero bloccate ritornano immediatamente, restituendo
-l'errore \macro{EAGAIN}.
-
-L'utilizzo di questa modalità di I/O permette di risolvere il problema
-controllando a turno i vari file descriptor, in un ciclo in cui si ripete
-l'accesso fintanto che esso non viene garantito.  Ovviamente questa tecnica,
-detta \textit{polling}, è estremamente inefficiente: si tiene costantemente
-impiegata la CPU solo per eseguire in continuazione delle system call che
-nella gran parte dei casi falliranno. Per evitare questo, come vedremo in
-\secref{sec:file_multiplexing}, è stata introdotta una nuova interfaccia di
-programmazione, che comporta comunque l'uso della modalità di I/O non
-bloccante.
-
-\subsection{Le funzioni \func{poll} e \func{select}}
-\label{sec:file_multiplexing}
-
-Per superare il problema di dover usare il \textit{polling} controllare la
-disponibilità di accesso ad un file aperto in modalità non bloccante, sia BSD
-che System V hanno introdotto delle nuove funzioni in grado di sospendere
-l'esecuzione di un processo fino a che l'accesso diventi possibile; il primo
-ad introdurre questa nuova interfaccia, chiamata usualmente \textit{I/O
-  multiplexing}, è stato BSD, con l'introduzione della funzione \func{select},
-il cui prototipo è:
-\begin{prototype}{sys/select.h}
-  {int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
-    struct timeval *timeout)}
-
-Attende che un certo insieme di file descriptor cambi stato.
-  
-\bodydesc{La funzione restituisce il numero di file descriptor, anche nullo,
-  che hanno cambiato stato in caso di successo e -1 in caso di errore, nel
-  qual caso \var{errno} viene settata ai valori:
-  \begin{errlist}
-  \item[\macro{EBADF}] Si è specificato un file descriptor sbagliato in uno
-  degli insiemi.
-  \item[\macro{EINTR}] La funzione è stata interrotta da un segnale.
-  \item[\macro{EINVAL}] Si è specificato per \param{n} un valore negativo.
-  \end{errlist}
-  ed inoltre \macro{ENOMEM}.
-}
-\end{prototype}
-
-La funzione mette il processo in stato di \textit{sleep} (vedi
-\tabref{tab:proc_proc_states}) fintanto che non viene rilevate dell'attività
-sull'insieme dei file descriptor specificati (\param{readfds},
-\param{writefds} e \param{exceptfds}), per un tempo massimo specificato da
-\param{timeout}. 
-
-Per specificare quali file descriptor si intende selezionare, la funzione usa
-un particolare oggetto, il \textit{file descriptor set}, identificato dal tipo
-\type{fd\_set}, che serve ad identificare un insieme di file descriptor, in
-maniera analoga a come un \textit{signal set} (vedi \secref{sec:sig_sigset})
-identifica un insieme di segnali. Per la manipolazione di questi \textit{file
-  descriptor set} si possono usare delle opportune macro di preprocessore:
-\begin{functions}
-  \headdecl{sys/select.h}
-  \funcdecl{FD\_ZERO(fd\_set *set)}
-  Inizializza l'insieme (vuoto).
-
-  \funcdecl{FD\_SET(int fd, fd\_set *set)}
-  Inserisce il file descriptor \param{fd} nell'insieme.
-
-  \funcdecl{FD\_CLR(int fd, fd\_set *set)}
-  Rimuove il file descriptor \param{fd} nell'insieme.
-  
-  \funcdecl{FD\_ISSET(int fd, fd\_set *set)}
-  Controlla se il file descriptor \param{fd} è nell'insieme.
-\end{functions}
+Benché possa risultare utile per sincronizzare l'accesso ad uno stesso file da
+parte di più processi, l'uso dei \textit{file lease} non consente comunque di
+risolvere il problema di rilevare automaticamente quando un file o una
+directory vengono modificati,\footnote{questa funzionalità venne aggiunta
+  principalmente ad uso di Samba per poter facilitare l'emulazione del
+  comportamento di Windows sui file, ma ad oggi viene considerata una
+  interfaccia mal progettata ed il suo uso è fortemente sconsigliato a favore
+  di \textit{inotify}.} che è quanto necessario ad esempio ai programma di
+gestione dei file dei vari desktop grafici.
 
-In genere un \textit{file descriptor set} può contenere fino ad un massimo di
-\macro{FD\_SETSIZE} file descriptor.  Questo a seconda del sistema può essere
-il limite del numero massimo di file aperti\footnote{ad esempio in Linux, fino
-  alla serie 2.0.x, c'era un limite di 256 file per processo.}, ma quando,
-come nelle versioni più recenti del kernel, questo limite non c'è un massimo,
-esso indica le dimensioni in numero di bit utilizzabili per l'insieme.
+\itindbeg{dnotify}
 
-La funzione richiede di specificare tre insiemi distinti di file descriptor;
-il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
-input in lettura, il secondo, \param{writefds} per verificare la possibilità
-di scrivere ed il terzo, \param{exceptfds}, per verificare l'esistenza di
-eccezioni. I corrispondenti valori dei \textit{file descriptor set} saranno
-modificati di conseguenza per mostrare quale dei file descriptor ha cambiato
-stato.
+Per risolvere questo problema a partire dal kernel 2.4 è stata allora creata
+un'altra interfaccia,\footnote{si ricordi che anche questa è una interfaccia
+  specifica di Linux che deve essere evitata se si vogliono scrivere programmi
+  portabili, e che le funzionalità illustrate sono disponibili soltanto se è
+  stata definita la macro \macro{\_GNU\_SOURCE}.} chiamata \textit{dnotify},
+che consente di richiedere una notifica quando una directory, o uno qualunque
+dei file in essa contenuti, viene modificato.  Come per i \textit{file lease}
+la notifica avviene di default attraverso il segnale \signal{SIGIO}, ma se ne
+può utilizzare un altro, e di nuovo, per le ragioni già esposte in precedenza,
+è opportuno che si utilizzino dei segnali \textit{real-time}.  Inoltre, come
+in precedenza, si potrà ottenere nel gestore del segnale il file descriptor
+che è stato modificato tramite il contenuto della struttura
+\struct{siginfo\_t}.
 
+\itindend{file~lease}
 
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{8cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{DN\_ACCESS} & Un file è stato acceduto, con l'esecuzione di una fra
+                         \func{read}, \func{pread}, \func{readv}.\\ 
+    \const{DN\_MODIFY} & Un file è stato modificato, con l'esecuzione di una
+                         fra \func{write}, \func{pwrite}, \func{writev}, 
+                         \func{truncate}, \func{ftruncate}.\\ 
+    \const{DN\_CREATE} & È stato creato un file nella directory, con
+                         l'esecuzione di una fra \func{open}, \func{creat},
+                         \func{mknod}, \func{mkdir}, \func{link},
+                         \func{symlink}, \func{rename} (da un'altra
+                         directory).\\
+    \const{DN\_DELETE} & È stato cancellato un file dalla directory con
+                         l'esecuzione di una fra \func{unlink}, \func{rename}
+                         (su un'altra directory), \func{rmdir}.\\
+    \const{DN\_RENAME} & È stato rinominato un file all'interno della
+                         directory (con \func{rename}).\\
+    \const{DN\_ATTRIB} & È stato modificato un attributo di un file con
+                         l'esecuzione di una fra \func{chown}, \func{chmod},
+                         \func{utime}.\\ 
+    \const{DN\_MULTISHOT}& Richiede una notifica permanente di tutti gli
+                         eventi.\\ 
+    \hline    
+  \end{tabular}
+  \caption{Le costanti che identificano le varie classi di eventi per i quali
+    si richiede la notifica con il comando \const{F\_NOTIFY} di \func{fcntl}.} 
+  \label{tab:file_notify}
+\end{table}
 
+Ci si può registrare per le notifiche dei cambiamenti al contenuto di una
+certa directory eseguendo la funzione \func{fcntl} su un file descriptor
+associato alla stessa con il comando \const{F\_NOTIFY}. In questo caso
+l'argomento \param{arg} di \func{fcntl} serve ad indicare per quali classi
+eventi si vuole ricevere la notifica, e prende come valore una maschera
+binaria composta dall'OR aritmetico di una o più delle costanti riportate in
+tab.~\ref{tab:file_notify}.
 
+A meno di non impostare in maniera esplicita una notifica permanente usando il
+valore \const{DN\_MULTISHOT}, la notifica è singola: viene cioè inviata una
+sola volta quando si verifica uno qualunque fra gli eventi per i quali la si è
+richiesta. Questo significa che un programma deve registrarsi un'altra volta
+se desidera essere notificato di ulteriori cambiamenti. Se si eseguono diverse
+chiamate con \const{F\_NOTIFY} e con valori diversi per \param{arg} questi
+ultimi si \textsl{accumulano}; cioè eventuali nuovi classi di eventi
+specificate in chiamate successive vengono aggiunte a quelle già impostate
+nelle precedenti.  Se si vuole rimuovere la notifica si deve invece
+specificare un valore nullo.
 
-Come accennato l'interfaccia di \func{select} è una estensione aggiunta BSD, e
-poi entrata a far parte di POSIX; allo stesso tempo System V aveva introdotto
-una interfaccia alternativa, basata sulla funzione \func{poll}, il cui
-prototipo è:
-\begin{prototype}{sys/poll.h}
-  {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
+\itindbeg{inotify}
 
-La funzione attente un cambiamento di stato per uno dei file descriptor
-specificati da \param{ufds}.
-  
-\bodydesc{La funzione restituisce il numero di file descriptor con attività in
-  caso di successo, o 0 se c'è stato un timeout; in caso di errore viene
-  restituito  -1 ed \var{errno} viene settata ai valori:
+Il maggiore problema di \textit{dnotify} è quello della scalabilità: si deve
+usare un file descriptor per ciascuna directory che si vuole tenere sotto
+controllo, il che porta facilmente ad avere un eccesso di file aperti. Inoltre
+quando la directory che si controlla è all'interno di un dispositivo
+rimovibile, mantenere il relativo file descriptor aperto comporta
+l'impossibilità di smontare il dispositivo e di rimuoverlo, il che in genere
+complica notevolmente la gestione dell'uso di questi dispositivi.
+
+Un altro problema è che l'interfaccia di \textit{dnotify} consente solo di
+tenere sotto controllo il contenuto di una directory; la modifica di un file
+viene segnalata, ma poi è necessario verificare di quale file si tratta
+(operazione che può essere molto onerosa quando una directory contiene un gran
+numero di file).  Infine l'uso dei segnali come interfaccia di notifica
+comporta tutti i problemi di gestione visti in sez.~\ref{sec:sig_management} e
+sez.~\ref{sec:sig_adv_control}.  Per tutta questa serie di motivi in generale
+quella di \textit{dnotify} viene considerata una interfaccia di usabilità
+problematica ed il suo uso oggi è fortemente sconsigliato.
+
+\itindend{dnotify}
+
+Per risolvere i problemi appena illustrati è stata introdotta una nuova
+interfaccia per l'osservazione delle modifiche a file o directory, chiamata
+\textit{inotify}.\footnote{l'interfaccia è disponibile a partire dal kernel
+  2.6.13, le relative funzioni sono state introdotte nelle glibc 2.4.}  Anche
+questa è una interfaccia specifica di Linux (pertanto non deve essere usata se
+si devono scrivere programmi portabili), ed è basata sull'uso di una coda di
+notifica degli eventi associata ad un singolo file descriptor, il che permette
+di risolvere il principale problema di \itindex{dnotify} \textit{dnotify}.  La
+coda viene creata attraverso la funzione di sistema \funcd{inotify\_init}, il
+cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_init(void)}
+\fdesc{Inizializza una istanza di \textit{inotify}.}
+}
+
+{La funzione ritornaun file descriptor in caso di successo, o $-1$ in caso di
+  errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EMFILE}] si è raggiunto il numero massimo di istanze di
+    \textit{inotify} consentite all'utente.
+  \item[\errcode{ENFILE}] si è raggiunto il massimo di file descriptor aperti
+    nel sistema.
+  \item[\errcode{ENOMEM}] non c'è sufficiente memoria nel kernel per creare
+    l'istanza.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione non prende alcun argomento; inizializza una istanza di
+\textit{inotify} e restituisce un file descriptor attraverso il quale verranno
+effettuate le operazioni di notifica; si tratta di un file descriptor speciale
+che non è associato a nessun file su disco, e che viene utilizzato solo per
+notificare gli eventi che sono stati posti in osservazione. Per evitare abusi
+delle risorse di sistema è previsto che un utente possa utilizzare un numero
+limitato di istanze di \textit{inotify}; il valore di default del limite è di
+128, ma questo valore può essere cambiato con \func{sysctl} o usando il file
+\sysctlfile{fs/inotify/max\_user\_instances}.
+
+Dato che questo file descriptor non è associato a nessun file o directory
+reale, l'inconveniente di non poter smontare un filesystem i cui file sono
+tenuti sotto osservazione viene completamente eliminato; anzi, una delle
+capacità dell'interfaccia di \textit{inotify} è proprio quella di notificare
+il fatto che il filesystem su cui si trova il file o la directory osservata è
+stato smontato.
+
+Inoltre trattandosi di un file descriptor a tutti gli effetti, esso potrà
+essere utilizzato come argomento per le funzioni \func{select} e \func{poll} e
+con l'interfaccia di \textit{epoll}, ed a partire dal kernel 2.6.25 è stato
+introdotto anche il supporto per il \itindex{signal~driven~I/O}
+\texttt{signal-driven I/O}.  Siccome gli eventi vengono notificati come dati
+disponibili in lettura, dette funzioni ritorneranno tutte le volte che si avrà
+un evento di notifica. 
+
+Così, invece di dover utilizzare i segnali, considerati una pessima scelta dal
+punto di vista dell'interfaccia utente, si potrà gestire l'osservazione degli
+eventi con una qualunque delle modalità di \textit{I/O multiplexing}
+illustrate in sez.~\ref{sec:file_multiplexing}. Qualora si voglia cessare
+l'osservazione, sarà sufficiente chiudere il file descriptor e tutte le
+risorse allocate saranno automaticamente rilasciate. Infine l'interfaccia di
+\textit{inotify} consente di mettere sotto osservazione, oltre che una
+directory, anche singoli file.
+
+Una volta creata la coda di notifica si devono definire gli eventi da tenere
+sotto osservazione; questo viene fatto attraverso una \textsl{lista di
+  osservazione} (o \textit{watch list}) che è associata alla coda. Per gestire
+la lista di osservazione l'interfaccia fornisce due funzioni di sistema, la
+prima di queste è \funcd{inotify\_add\_watch}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_add\_watch(int fd, const char *pathname, uint32\_t mask)}
+\fdesc{Aggiunge un evento di osservazione a una lista di osservazione.} 
+}
+
+{La funzione ritorna un valore positivo in caso di successo, o $-1$ per un
+  errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EACCES}] non si ha accesso in lettura al file indicato.
+  \item[\errcode{EINVAL}] \param{mask} non contiene eventi legali o \param{fd}
+    non è un file descriptor di \textit{inotify}.
+  \item[\errcode{ENOSPC}] si è raggiunto il numero massimo di voci di
+    osservazione o il kernel non ha potuto allocare una risorsa necessaria.
+  \end{errlist}
+  ed inoltre \errval{EFAULT}, \errval{ENOMEM} e \errval{EBADF} nel loro
+  significato generico.}
+\end{funcproto}
+
+La funzione consente di creare un ``\textsl{osservatore}'' (il cosiddetto
+``\textit{watch}'') nella lista di osservazione di una coda di notifica, che
+deve essere indicata specificando il file descriptor ad essa associato
+nell'argomento \param{fd}, che ovviamente dovrà essere un file descriptor
+creato con \func{inotify\_init}.  Il file o la directory da porre sotto
+osservazione vengono invece indicati per nome, da passare
+nell'argomento \param{pathname}.  Infine il terzo argomento, \param{mask},
+indica che tipo di eventi devono essere tenuti sotto osservazione e le
+modalità della stessa.  L'operazione può essere ripetuta per tutti i file e le
+directory che si vogliono tenere sotto osservazione,\footnote{anche in questo
+  caso c'è un limite massimo che di default è pari a 8192, ed anche questo
+  valore può essere cambiato con \func{sysctl} o usando il file
+  \sysctlfile{fs/inotify/max\_user\_watches}.} e si utilizzerà sempre un solo
+file descriptor.
+
+Il tipo di evento che si vuole osservare deve essere specificato
+nell'argomento \param{mask} come maschera binaria, combinando i valori delle
+costanti riportate in tab.~\ref{tab:inotify_event_watch} che identificano i
+singoli bit della maschera ed il relativo significato. In essa si sono marcati
+con un ``$\bullet$'' gli eventi che, quando specificati per una directory,
+vengono osservati anche su tutti i file che essa contiene.  Nella seconda
+parte della tabella si sono poi indicate alcune combinazioni predefinite dei
+flag della prima parte.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|c|p{8cm}|}
+    \hline
+    \textbf{Valore}  & & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{IN\_ACCESS}        &$\bullet$& C'è stato accesso al file in
+                                          lettura.\\  
+    \const{IN\_ATTRIB}        &$\bullet$& Ci sono stati cambiamenti sui dati
+                                          dell'\itindex{inode} \textit{inode}
+                                          (o sugli attributi estesi, vedi
+                                          sez.~\ref{sec:file_xattr}).\\ 
+    \const{IN\_CLOSE\_WRITE}  &$\bullet$& È stato chiuso un file aperto in
+                                          scrittura.\\  
+    \const{IN\_CLOSE\_NOWRITE}&$\bullet$& È stato chiuso un file aperto in
+                                          sola lettura.\\
+    \const{IN\_CREATE}        &$\bullet$& È stato creato un file o una
+                                          directory in una directory sotto
+                                          osservazione.\\  
+    \const{IN\_DELETE}        &$\bullet$& È stato cancellato un file o una
+                                          directory in una directory sotto
+                                          osservazione.\\ 
+    \const{IN\_DELETE\_SELF}  & --      & È stato cancellato il file (o la
+                                          directory) sotto osservazione.\\ 
+    \const{IN\_MODIFY}        &$\bullet$& È stato modificato il file.\\ 
+    \const{IN\_MOVE\_SELF}    &         & È stato rinominato il file (o la
+                                          directory) sotto osservazione.\\ 
+    \const{IN\_MOVED\_FROM}   &$\bullet$& Un file è stato spostato fuori dalla
+                                          directory sotto osservazione.\\ 
+    \const{IN\_MOVED\_TO}     &$\bullet$& Un file è stato spostato nella
+                                          directory sotto osservazione.\\ 
+    \const{IN\_OPEN}          &$\bullet$& Un file è stato aperto.\\ 
+    \hline    
+    \const{IN\_CLOSE}         &         & Combinazione di
+                                          \const{IN\_CLOSE\_WRITE} e
+                                          \const{IN\_CLOSE\_NOWRITE}.\\  
+    \const{IN\_MOVE}          &         & Combinazione di
+                                          \const{IN\_MOVED\_FROM} e
+                                          \const{IN\_MOVED\_TO}.\\
+    \const{IN\_ALL\_EVENTS}   &         & Combinazione di tutti i flag
+                                          possibili.\\
+    \hline    
+  \end{tabular}
+  \caption{Le costanti che identificano i bit della maschera binaria
+    dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano il
+    tipo di evento da tenere sotto osservazione.} 
+  \label{tab:inotify_event_watch}
+\end{table}
+
+Oltre ai flag di tab.~\ref{tab:inotify_event_watch}, che indicano il tipo di
+evento da osservare e che vengono utilizzati anche in uscita per indicare il
+tipo di evento avvenuto, \func{inotify\_add\_watch} supporta ulteriori
+flag,\footnote{i flag \const{IN\_DONT\_FOLLOW}, \const{IN\_MASK\_ADD} e
+  \const{IN\_ONLYDIR} sono stati introdotti a partire dalle glibc 2.5, se si
+  usa la versione 2.4 è necessario definirli a mano.}  riportati in
+tab.~\ref{tab:inotify_add_watch_flag}, che indicano le modalità di
+osservazione (da passare sempre nell'argomento \param{mask}) e che al
+contrario dei precedenti non vengono mai impostati nei risultati in uscita.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{8cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{IN\_DONT\_FOLLOW}& Non dereferenzia \param{pathname} se questo è un
+                              link simbolico.\\
+    \const{IN\_MASK\_ADD}   & Aggiunge a quelli già impostati i flag indicati
+                              nell'argomento \param{mask}, invece di
+                              sovrascriverli.\\
+    \const{IN\_ONESHOT}     & Esegue l'osservazione su \param{pathname} per una
+                              sola volta, rimuovendolo poi dalla \textit{watch
+                                list}.\\ 
+    \const{IN\_ONLYDIR}     & Se \param{pathname} è una directory riporta
+                              soltanto gli eventi ad essa relativi e non
+                              quelli per i file che contiene.\\ 
+    \hline    
+  \end{tabular}
+  \caption{Le costanti che identificano i bit della maschera binaria
+    dell'argomento \param{mask} di \func{inotify\_add\_watch} che indicano le
+    modalità di osservazione.} 
+  \label{tab:inotify_add_watch_flag}
+\end{table}
+
+Se non esiste nessun \textit{watch} per il file o la directory specificata
+questo verrà creato per gli eventi specificati dall'argomento \param{mask},
+altrimenti la funzione sovrascriverà le impostazioni precedenti, a meno che
+non si sia usato il flag \const{IN\_MASK\_ADD}, nel qual caso gli eventi
+specificati saranno aggiunti a quelli già presenti.
+
+Come accennato quando si tiene sotto osservazione una directory vengono
+restituite le informazioni sia riguardo alla directory stessa che ai file che
+essa contiene; questo comportamento può essere disabilitato utilizzando il
+flag \const{IN\_ONLYDIR}, che richiede di riportare soltanto gli eventi
+relativi alla directory stessa. Si tenga presente inoltre che quando si
+osserva una directory vengono riportati solo gli eventi sui file che essa
+contiene direttamente, non quelli relativi a file contenuti in eventuali
+sottodirectory; se si vogliono osservare anche questi sarà necessario creare
+ulteriori \textit{watch} per ciascuna sottodirectory.
+
+Infine usando il flag \const{IN\_ONESHOT} è possibile richiedere una notifica
+singola;\footnote{questa funzionalità però è disponibile soltanto a partire dal
+  kernel 2.6.16.} una volta verificatosi uno qualunque fra gli eventi
+richiesti con \func{inotify\_add\_watch} l'\textsl{osservatore} verrà
+automaticamente rimosso dalla lista di osservazione e nessun ulteriore evento
+sarà più notificato.
+
+In caso di successo \func{inotify\_add\_watch} ritorna un intero positivo,
+detto \textit{watch descriptor}, che identifica univocamente un
+\textsl{osservatore} su una coda di notifica; esso viene usato per farvi
+riferimento sia riguardo i risultati restituiti da \textit{inotify}, che per
+la eventuale rimozione dello stesso. 
+
+La seconda funzione di sistema per la gestione delle code di notifica, che
+permette di rimuovere un \textsl{osservatore}, è \funcd{inotify\_rm\_watch},
+ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/inotify.h}
+\fdecl{int inotify\_rm\_watch(int fd, uint32\_t wd)}
+\fdesc{Rimuove un \textsl{osservatore} da una coda di notifica.} 
+}
+
+{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}] non si è specificato in \param{fd} un file descriptor
+    valido.
+  \item[\errcode{EINVAL}] il valore di \param{wd} non è corretto, o \param{fd}
+    non è associato ad una coda di notifica.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione rimuove dalla coda di notifica identificata dall'argomento
+\param{fd} l'osservatore identificato dal \textit{watch descriptor}
+\param{wd}; ovviamente deve essere usato per questo argomento un valore
+ritornato da \func{inotify\_add\_watch}, altrimenti si avrà un errore di
+\errval{EINVAL}. In caso di successo della rimozione, contemporaneamente alla
+cancellazione dell'osservatore, sulla coda di notifica verrà generato un
+evento di tipo \const{IN\_IGNORED} (vedi
+tab.~\ref{tab:inotify_read_event_flag}). Si tenga presente che se un file
+viene cancellato o un filesystem viene smontato i relativi osservatori vengono
+rimossi automaticamente e non è necessario utilizzare
+\func{inotify\_rm\_watch}.
+
+Come accennato l'interfaccia di \textit{inotify} prevede che gli eventi siano
+notificati come dati presenti in lettura sul file descriptor associato alla
+coda di notifica. Una applicazione pertanto dovrà leggere i dati da detto file
+con una \func{read}, che ritornerà sul buffer i dati presenti nella forma di
+una o più strutture di tipo \struct{inotify\_event} (la cui definizione è
+riportata in fig.~\ref{fig:inotify_event}). Qualora non siano presenti dati la
+\func{read} si bloccherà (a meno di non aver impostato il file descriptor in
+modalità non bloccante) fino all'arrivo di almeno un evento.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{0.90\textwidth}
+    \includestruct{listati/inotify_event.h}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{inotify\_event} usata dall'interfaccia di
+    \textit{inotify} per riportare gli eventi.}
+  \label{fig:inotify_event}
+\end{figure}
+
+Una ulteriore caratteristica dell'interfaccia di \textit{inotify} è che essa
+permette di ottenere con \func{ioctl}, come per i file descriptor associati ai
+socket (si veda sez.~\ref{sec:sock_ioctl_IP}), il numero di byte disponibili
+in lettura sul file descriptor, utilizzando su di esso l'operazione
+\const{FIONREAD}.\footnote{questa è una delle operazioni speciali per i file
+  (vedi sez.~\ref{sec:file_fcntl_ioctl}), che è disponibile solo per i socket
+  e per i file descriptor creati con \func{inotify\_init}.} Si può così
+utilizzare questa operazione, oltre che per predisporre una operazione di
+lettura con un buffer di dimensioni adeguate, anche per ottenere rapidamente
+il numero di file che sono cambiati.
+
+Una volta effettuata la lettura con \func{read} a ciascun evento sarà
+associata una struttura \struct{inotify\_event} contenente i rispettivi dati.
+Per identificare a quale file o directory l'evento corrisponde viene
+restituito nel campo \var{wd} il \textit{watch descriptor} con cui il relativo
+osservatore è stato registrato. Il campo \var{mask} contiene invece una
+maschera di bit che identifica il tipo di evento verificatosi; in essa
+compariranno sia i bit elencati nella prima parte di
+tab.~\ref{tab:inotify_event_watch}, che gli eventuali valori aggiuntivi di
+tab.~\ref{tab:inotify_read_event_flag} (questi compaiono solo nel campo
+\var{mask} di \struct{inotify\_event}, e non sono utilizzabili in fase di
+registrazione dell'osservatore).
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{IN\_IGNORED}    & L'osservatore è stato rimosso, sia in maniera 
+                             esplicita con l'uso di \func{inotify\_rm\_watch}, 
+                             che in maniera implicita per la rimozione 
+                             dell'oggetto osservato o per lo smontaggio del
+                             filesystem su cui questo si trova.\\
+    \const{IN\_ISDIR}      & L'evento avvenuto fa riferimento ad una directory
+                             (consente così di distinguere, quando si pone
+                             sotto osservazione una directory, fra gli eventi
+                             relativi ad essa e quelli relativi ai file che
+                             essa contiene).\\
+    \const{IN\_Q\_OVERFLOW}& Si sono eccedute le dimensioni della coda degli
+                             eventi (\textit{overflow} della coda); in questo
+                             caso il valore di \var{wd} è $-1$.\footnotemark\\
+    \const{IN\_UNMOUNT}    & Il filesystem contenente l'oggetto posto sotto
+                             osservazione è stato smontato.\\
+    \hline    
+  \end{tabular}
+  \caption{Le costanti che identificano i bit aggiuntivi usati nella maschera
+    binaria del campo \var{mask} di \struct{inotify\_event}.} 
+  \label{tab:inotify_read_event_flag}
+\end{table}
+
+\footnotetext{la coda di notifica ha una dimensione massima che viene
+  controllata dal parametro di sistema
+  \sysctlfile{fs/inotify/max\_queued\_events}, che indica il numero massimo di
+  eventi che possono essere mantenuti sulla stessa; quando detto valore viene
+  ecceduto gli ulteriori eventi vengono scartati, ma viene comunque generato
+  un evento di tipo \const{IN\_Q\_OVERFLOW}.}
+
+Il campo \var{cookie} contiene invece un intero univoco che permette di
+identificare eventi correlati (per i quali avrà lo stesso valore), al momento
+viene utilizzato soltanto per rilevare lo spostamento di un file, consentendo
+così all'applicazione di collegare la corrispondente coppia di eventi
+\const{IN\_MOVED\_TO} e \const{IN\_MOVED\_FROM}.
 
-.}
-\end{prototype}
+Infine due campi \var{name} e \var{len} sono utilizzati soltanto quando
+l'evento è relativo ad un file presente in una directory posta sotto
+osservazione, in tal caso essi contengono rispettivamente il nome del file
+(come \itindsub{pathname}{relativo} \textit{pathname} relativo alla directory
+osservata) e la relativa dimensione in byte. Il campo \var{name} viene sempre
+restituito come stringa terminata da NUL, con uno o più zeri di terminazione,
+a seconda di eventuali necessità di allineamento del risultato, ed il valore
+di \var{len} corrisponde al totale della dimensione di \var{name}, zeri
+aggiuntivi compresi. La stringa con il nome del file viene restituita nella
+lettura subito dopo la struttura \struct{inotify\_event}; questo significa che
+le dimensioni di ciascun evento di \textit{inotify} saranno pari a
+\code{sizeof(\struct{inotify\_event}) + len}.
 
+Vediamo allora un esempio dell'uso dell'interfaccia di \textit{inotify} con un
+semplice programma che permette di mettere sotto osservazione uno o più file e
+directory. Il programma si chiama \texttt{inotify\_monitor.c} ed il codice
+completo è disponibile coi sorgenti allegati alla guida, il corpo principale
+del programma, che non contiene la sezione di gestione delle opzioni e le
+funzioni di ausilio è riportato in fig.~\ref{fig:inotify_monitor_example}.
 
+\begin{figure}[!htbp]
+  \footnotesize \centering
+  \begin{minipage}[c]{\codesamplewidth}
+    \includecodesample{listati/inotify_monitor.c}
+  \end{minipage}
+  \normalsize
+  \caption{Esempio di codice che usa l'interfaccia di \textit{inotify}.}
+  \label{fig:inotify_monitor_example}
+\end{figure}
 
+Una volta completata la scansione delle opzioni il corpo del programma inizia
+controllando (\texttt{\small 11-15}) che sia rimasto almeno un argomento che
+indichi quale file o directory mettere sotto osservazione (e qualora questo
+non avvenga esce stampando la pagina di aiuto); dopo di che passa
+(\texttt{\small 16-20}) all'inizializzazione di \textit{inotify} ottenendo con
+\func{inotify\_init} il relativo file descriptor (o si esce in caso di
+errore).
 
-\subsection{L'I/O asincrono}
+Il passo successivo è aggiungere (\texttt{\small 21-30}) alla coda di
+notifica gli opportuni osservatori per ciascuno dei file o directory indicati
+all'invocazione del comando; questo viene fatto eseguendo un ciclo
+(\texttt{\small 22-29}) fintanto che la variabile \var{i}, inizializzata a
+zero (\texttt{\small 21}) all'inizio del ciclo, è minore del numero totale di
+argomenti rimasti. All'interno del ciclo si invoca (\texttt{\small 23})
+\func{inotify\_add\_watch} per ciascuno degli argomenti, usando la maschera
+degli eventi data dalla variabile \var{mask} (il cui valore viene impostato
+nella scansione delle opzioni), in caso di errore si esce dal programma
+altrimenti si incrementa l'indice (\texttt{\small 29}).
+
+Completa l'inizializzazione di \textit{inotify} inizia il ciclo principale
+(\texttt{\small 32-56}) del programma, nel quale si resta in attesa degli
+eventi che si intendono osservare. Questo viene fatto eseguendo all'inizio del
+ciclo (\texttt{\small 33}) una \func{read} che si bloccherà fintanto che non
+si saranno verificati eventi.
+
+Dato che l'interfaccia di \textit{inotify} può riportare anche più eventi in
+una sola lettura, si è avuto cura di passare alla \func{read} un buffer di
+dimensioni adeguate, inizializzato in (\texttt{\small 7}) ad un valore di
+approssimativamente 512 eventi (si ricordi che la quantità di dati restituita
+da \textit{inotify} è variabile a causa della diversa lunghezza del nome del
+file restituito insieme a \struct{inotify\_event}). In caso di errore di
+lettura (\texttt{\small 35-40}) il programma esce con un messaggio di errore
+(\texttt{\small 37-39}), a meno che non si tratti di una interruzione della
+\textit{system call}, nel qual caso (\texttt{\small 36}) si ripete la lettura.
+
+Se la lettura è andata a buon fine invece si esegue un ciclo (\texttt{\small
+  43-52}) per leggere tutti gli eventi restituiti, al solito si inizializza
+l'indice \var{i} a zero (\texttt{\small 42}) e si ripetono le operazioni
+(\texttt{\small 43}) fintanto che esso non supera il numero di byte restituiti
+in lettura. Per ciascun evento all'interno del ciclo si assegna alla variabile
+\var{event} (si noti come si sia eseguito un opportuno \textit{casting} del
+puntatore) l'indirizzo nel buffer della corrispondente struttura
+\struct{inotify\_event} (\texttt{\small 44}), e poi si stampano il numero di
+\textit{watch descriptor} (\texttt{\small 45}) ed il file a cui questo fa
+riferimento (\texttt{\small 46}), ricavato dagli argomenti passati a riga di
+comando sfruttando il fatto che i \textit{watch descriptor} vengono assegnati
+in ordine progressivo crescente a partire da 1.
+
+Qualora sia presente il riferimento ad un nome di file associato all'evento lo
+si stampa (\texttt{\small 47-49}); si noti come in questo caso si sia
+controllato il valore del campo \var{event->len} e non il fatto che
+\var{event->name} riporti o meno un puntatore nullo. L'interfaccia infatti,
+qualora il nome non sia presente, non tocca il campo \var{event->name}, che
+si troverà pertanto a contenere quello che era precedentemente presente nella
+rispettiva locazione di memoria, nel caso più comune il puntatore al nome di
+un file osservato in precedenza.
+
+Si utilizza poi (\texttt{\small 50}) la funzione \code{printevent}, che
+interpreta il valore del campo \var{event->mask}, per stampare il tipo di
+eventi accaduti.\footnote{per il relativo codice, che non riportiamo in quanto
+  non essenziale alla comprensione dell'esempio, si possono utilizzare
+  direttamente i sorgenti allegati alla guida.} Infine (\texttt{\small 51}) si
+provvede ad aggiornare l'indice \var{i} per farlo puntare all'evento
+successivo.
+
+Se adesso usiamo il programma per mettere sotto osservazione una directory, e
+da un altro terminale eseguiamo il comando \texttt{ls} otterremo qualcosa del
+tipo di:
+\begin{Console}
+piccardi@gethen:~/gapil/sources$ \textbf{./inotify_monitor -a /home/piccardi/gapil/}
+Watch descriptor 1
+Observed event on /home/piccardi/gapil/
+IN_OPEN, 
+Watch descriptor 1
+Observed event on /home/piccardi/gapil/
+IN_CLOSE_NOWRITE, 
+\end{Console}
+%$
+
+I lettori più accorti si saranno resi conto che nel ciclo di lettura degli
+eventi appena illustrato non viene trattato il caso particolare in cui la
+funzione \func{read} restituisce in \var{nread} un valore nullo. Lo si è fatto
+perché con \textit{inotify} il ritorno di una \func{read} con un valore nullo
+avviene soltanto, come forma di avviso, quando si sia eseguita la funzione
+specificando un buffer di dimensione insufficiente a contenere anche un solo
+evento. Nel nostro caso le dimensioni erano senz'altro sufficienti, per cui
+tale evenienza non si verificherà mai.
+
+Ci si potrà però chiedere cosa succede se il buffer è sufficiente per un
+evento, ma non per tutti gli eventi verificatisi. Come si potrà notare nel
+codice illustrato in precedenza non si è presa nessuna precauzione per
+verificare che non ci fossero stati troncamenti dei dati. Anche in questo caso
+il comportamento scelto è corretto, perché l'interfaccia di \textit{inotify}
+garantisce automaticamente, anche quando ne sono presenti in numero maggiore,
+di restituire soltanto il numero di eventi che possono rientrare completamente
+nelle dimensioni del buffer specificato.\footnote{si avrà cioè, facendo
+  riferimento sempre al codice di fig.~\ref{fig:inotify_monitor_example}, che
+  \var{read} sarà in genere minore delle dimensioni di \var{buffer} ed uguale
+  soltanto qualora gli eventi corrispondano esattamente alle dimensioni di
+  quest'ultimo.} Se gli eventi sono di più saranno restituiti solo quelli che
+entrano interamente nel buffer e gli altri saranno restituiti alla successiva
+chiamata di \func{read}.
+
+Infine un'ultima caratteristica dell'interfaccia di \textit{inotify} è che gli
+eventi restituiti nella lettura formano una sequenza ordinata, è cioè
+garantito che se si esegue uno spostamento di un file gli eventi vengano
+generati nella sequenza corretta. L'interfaccia garantisce anche che se si
+verificano più eventi consecutivi identici (vale a dire con gli stessi valori
+dei campi \var{wd}, \var{mask}, \var{cookie}, e \var{name}) questi vengono
+raggruppati in un solo evento.
+
+\itindend{inotify}
+
+% TODO trattare fanotify, vedi http://lwn.net/Articles/339399/ e 
+% http://lwn.net/Articles/343346/ (incluso nel 2.6.36)
+
+
+\subsection{L'interfaccia POSIX per l'I/O asincrono}
 \label{sec:file_asyncronous_io}
 
-Una modalità alternativa all'uso dell'I/O non bloccante è quella di fare
-ricorso all'I/O asincrono. Abbiamo accennato in \secref{sec:file_open} che è
-possibile, attraverso l'uso del flag \macro{O\_ASYNC}, aprire un file in
-modalità asincrona, così come è possibile settare questo flag attraverso l'uso
-di \func{fcntl}.
+Una modalità alternativa all'uso dell'\textit{I/O multiplexing} per gestione
+dell'I/O simultaneo su molti file è costituita dal cosiddetto \textsl{I/O
+  asincrono} o ``AIO''. Il concetto base dell'\textsl{I/O asincrono} è che le
+funzioni di I/O non attendono il completamento delle operazioni prima di
+ritornare, così che il processo non viene bloccato.  In questo modo diventa ad
+esempio possibile effettuare una richiesta preventiva di dati, in modo da
+poter effettuare in contemporanea le operazioni di calcolo e quelle di I/O.
+
+Benché la modalità di apertura asincrona di un file vista in
+sez.~\ref{sec:signal_driven_io} possa risultare utile in varie occasioni (in
+particolar modo con i socket e gli altri file per i quali le funzioni di I/O
+sono \index{system~call~lente} \textit{system call} lente), essa è comunque
+limitata alla notifica della disponibilità del file descriptor per le
+operazioni di I/O, e non ad uno svolgimento asincrono delle medesime.  Lo
+standard POSIX.1b definisce una interfaccia apposita per l'I/O asincrono vero
+e proprio,\footnote{questa è stata ulteriormente perfezionata nelle successive
+  versioni POSIX.1-2001 e POSIX.1-2008.} che prevede un insieme di funzioni
+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 \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.
+
+Lo standard POSIX prevede che tutte le operazioni di I/O asincrono siano
+controllate attraverso l'uso di una apposita struttura \struct{aiocb} (il cui
+nome sta per \textit{asyncronous I/O control block}), che viene passata come
+argomento a tutte le funzioni dell'interfaccia. La sua definizione, come
+effettuata in \headfile{aio.h}, è riportata in
+fig.~\ref{fig:file_aiocb}. Nello steso file è definita la macro
+\macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la disponibilità
+dell'interfaccia per l'I/O asincrono.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{0.90\textwidth}
+    \includestruct{listati/aiocb.h}
+  \end{minipage}
+  \normalsize 
+  \caption{La struttura \structd{aiocb}, usata per il controllo dell'I/O
+    asincrono.}
+  \label{fig:file_aiocb}
+\end{figure}
+
+Le operazioni di I/O asincrono possono essere effettuate solo su un file già
+aperto; il file deve inoltre supportare la funzione \func{lseek}, pertanto
+terminali e \textit{pipe} sono esclusi. Non c'è limite al numero di operazioni
+contemporanee effettuabili su un singolo file.  Ogni operazione deve
+inizializzare opportunamente un \textit{control block}.  Il file descriptor su
+cui operare deve essere specificato tramite il campo \var{aio\_fildes}; dato
+che più operazioni possono essere eseguita in maniera asincrona, il concetto
+di posizione corrente sul file viene a mancare; pertanto si deve sempre
+specificare nel campo \var{aio\_offset} la posizione sul file da cui i dati
+saranno letti o scritti.  Nel campo \var{aio\_buf} deve essere specificato
+l'indirizzo del buffer usato per l'I/O, ed in \var{aio\_nbytes} la lunghezza
+del blocco di dati da trasferire.
+
+Il campo \var{aio\_reqprio} permette di impostare la priorità delle operazioni
+di I/O, in generale perché ciò sia possibile occorre che la piattaforma
+supporti questa caratteristica, questo viene indicato dal fatto che le macro
+\macro{\_POSIX\_PRIORITIZED\_IO}, e \macro{\_POSIX\_PRIORITY\_SCHEDULING} sono
+definite. La priorità viene impostata a partire da quella del processo
+chiamante (vedi sez.~\ref{sec:proc_priority}), cui viene sottratto il valore
+di questo campo.  Il campo \var{aio\_lio\_opcode} è usato solo dalla funzione
+\func{lio\_listio}, che, come vedremo, permette di eseguire con una sola
+chiamata una serie di operazioni, usando un vettore di \textit{control
+  block}. Tramite questo campo si specifica quale è la natura di ciascuna di
+esse.
+
+Infine il campo \var{aio\_sigevent} è una struttura di tipo \struct{sigevent}
+(illustrata in in fig.~\ref{fig:struct_sigevent}) che serve a specificare il
+modo in cui si vuole che venga effettuata la notifica del completamento delle
+operazioni richieste; per la trattazione delle modalità di utilizzo della
+stessa si veda quanto già visto in proposito in sez.~\ref{sec:sig_timer_adv}.
+
+Le due funzioni base dell'interfaccia per l'I/O asincrono sono
+\funcd{aio\_read} ed \funcd{aio\_write}.  Esse permettono di richiedere una
+lettura od una scrittura asincrona di dati usando la struttura \struct{aiocb}
+appena descritta; i rispettivi prototipi sono:
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_read(struct aiocb *aiocbp)}
+\fdesc{Richiede una lettura asincrona.} 
+\fdecl{int aio\_write(struct aiocb *aiocbp)}
+\fdesc{Richiede una scrittura asincrona.} 
+}
+
+{Le funzioni ritornano $0$ in caso di successo e $-1$ per un errore, nel qual
+  caso \var{errno} assumerà uno dei valori: 
+  \begin{errlist}
+  \item[\errcode{EAGAIN}] la coda delle richieste è momentaneamente piena.
+  \item[\errcode{EBADF}] si è specificato un file descriptor sbagliato.
+  \item[\errcode{EINVAL}] si è specificato un valore non valido per i campi
+    \var{aio\_offset} o \var{aio\_reqprio} di \param{aiocbp}.
+  \item[\errcode{ENOSYS}] la funzione non è implementata.
+  \end{errlist}
+}
+\end{funcproto}
+
+
+Entrambe le funzioni ritornano immediatamente dopo aver messo in coda la
+richiesta, o in caso di errore. Non è detto che gli errori \errcode{EBADF} ed
+\errcode{EINVAL} siano rilevati immediatamente al momento della chiamata,
+potrebbero anche emergere nelle fasi successive delle operazioni. Lettura e
+scrittura avvengono alla posizione indicata da \var{aio\_offset}, a meno che
+il file non sia stato aperto in \textit{append mode} (vedi
+sez.~\ref{sec:file_open_close}), nel qual caso le scritture vengono effettuate
+comunque alla fine del file, nell'ordine delle chiamate a \func{aio\_write}.
+
+Si tenga inoltre presente che deallocare la memoria indirizzata da
+\param{aiocbp} o modificarne i valori prima della conclusione di una
+operazione può dar luogo a risultati impredicibili, perché l'accesso ai vari
+campi per eseguire l'operazione può avvenire in un momento qualsiasi dopo la
+richiesta. Questo comporta che non si devono usare per \param{aiocbp}
+\index{variabili!automatiche} variabili automatiche e che non si deve
+riutilizzare la stessa struttura per un'altra operazione fintanto che la
+precedente non sia stata ultimata. In generale per ogni operazione si deve
+utilizzare una diversa struttura \struct{aiocb}.
+
+Dato che si opera in modalità asincrona, il successo di \func{aio\_read} o
+\func{aio\_write} non implica che le operazioni siano state effettivamente
+eseguite in maniera corretta; per verificarne l'esito l'interfaccia prevede
+altre due funzioni, che permettono di controllare lo stato di esecuzione. La
+prima è \funcd{aio\_error}, che serve a determinare un eventuale stato di
+errore; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_error(const struct aiocb *aiocbp)} 
+\fdesc{Determina lo stato di errore di una operazione di I/O asincrono.} 
+}
+
+{La funzione ritorna $0$ se le operazioni si sono concluse con successo,
+  altrimenti restituisce \errval{EINPROGRESS} se non sono concluse,
+  \errcode{ECANCELED} se sono state cancellate o il relativo codice di errore
+  se sono fallite.}
+\end{funcproto}
+
+Se l'operazione non si è ancora completata viene sempre restituito l'errore di
+\errcode{EINPROGRESS}, mentre se è stata cancellata ritorna
+\errcode{ECANCELED}. La funzione ritorna zero quando l'operazione si è
+conclusa con successo, altrimenti restituisce il codice dell'errore
+verificatosi, ed esegue la corrispondente impostazione di \var{errno}. Il
+codice può essere sia \errcode{EINVAL} ed \errcode{EBADF}, dovuti ad un valore
+errato per \param{aiocbp}, che uno degli errori possibili durante l'esecuzione
+dell'operazione di I/O richiesta, nel qual caso saranno restituiti, a seconda
+del caso, i codici di errore delle \textit{system call} \func{read},
+\func{write}, \func{fsync} e \func{fdatasync}.
+
+Una volta che si sia certi che le operazioni siano state concluse (cioè dopo
+che una chiamata ad \func{aio\_error} non ha restituito
+\errcode{EINPROGRESS}), si potrà usare la funzione \funcd{aio\_return}, che
+permette di verificare il completamento delle operazioni di I/O asincrono; il
+suo prototipo è:
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{ssize\_t aio\_return(const struct aiocb *aiocbp)}
+\fdesc{Ottiene lo stato dei risultati di una operazione di I/O asincrono.} 
+}
+
+{La funzione ritorna lo stato di uscita dell'operazione eseguita (il valore
+  che avrebbero restituito le equivalenti funzioni eseguite in maniera
+  sincrona).}
+\end{funcproto}
+
+La funzione recupera il valore dello stato di ritorno delle operazioni di I/O
+associate a \param{aiocbp} e deve essere chiamata una sola volta per ciascuna
+operazione asincrona, essa infatti fa sì che il sistema rilasci le risorse ad
+essa associate. É per questo motivo che occorre chiamare la funzione solo dopo
+che l'operazione cui \param{aiocbp} fa riferimento si è completata
+verificandolo con \func{aio\_error}, ed usarla una sola volta. Una chiamata
+precedente il completamento delle operazioni darebbe risultati indeterminati,
+così come chiamarla più di una volta.
+
+La funzione restituisce il valore di ritorno relativo all'operazione eseguita,
+così come ricavato dalla sottostante \textit{system call} (il numero di byte
+letti, scritti o il valore di ritorno di \func{fsync} o \func{fdatasync}).  É
+importante chiamare sempre questa funzione, altrimenti le risorse disponibili
+per le operazioni di I/O asincrono non verrebbero liberate, rischiando di
+arrivare ad un loro esaurimento.
+
+Oltre alle operazioni di lettura e scrittura l'interfaccia POSIX.1b mette a
+disposizione un'altra operazione, quella di sincronizzazione dell'I/O,
+compiuta dalla funzione \funcd{aio\_fsync}, che ha lo stesso effetto della
+analoga \func{fsync}, ma viene eseguita in maniera asincrona; il suo prototipo
+è:
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_fsync(int op, struct aiocb *aiocbp)} 
+\fdesc{Richiede la sincronizzazione dei dati su disco.} 
+}
+
+{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual
+  caso \var{errno} assumerà gli stessi valori visti \func{aio\_read} con lo
+  stesso significato.
+}
+\end{funcproto}
+
+La funzione richiede la sincronizzazione dei dati delle operazioni di I/O
+relative al file descriptor indicato in \texttt{aiocbp->aio\_fildes},
+ritornando immediatamente. Si tenga presente che la funzione mette
+semplicemente in coda la richiesta, l'esecuzione effettiva della
+sincronizzazione dovrà essere verificata con \func{aio\_error} e
+\func{aio\_return} come per le operazioni di lettura e
+scrittura. L'argomento \param{op} permette di indicare la modalità di
+esecuzione, se si specifica il valore \const{O\_DSYNC} le operazioni saranno
+completate con una chiamata a \func{fdatasync}, se si specifica
+\const{O\_SYNC} con una chiamata a \func{fsync} (per i dettagli vedi
+sez.~\ref{sec:file_sync}).
+
+Il successo della chiamata assicura la richiesta di sincronizzazione dei dati
+relativi operazioni di I/O asincrono richieste fino a quel momento, niente è
+garantito riguardo la sincronizzazione dei dati relativi ad eventuali
+operazioni richieste successivamente. Se si è specificato un meccanismo di
+notifica questo sarà innescato una volta che le operazioni di sincronizzazione
+dei dati saranno completate (\texttt{aio\_sigevent} è l'unico altro campo
+di \param{aiocbp} che viene usato.
+
+In alcuni casi può essere necessario interrompere le operazioni di I/O (in
+genere quando viene richiesta un'uscita immediata dal programma), per questo
+lo standard POSIX.1b prevede una funzione apposita, \funcd{aio\_cancel}, che
+permette di cancellare una operazione richiesta in precedenza; il suo
+prototipo è:
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_cancel(int fd, struct aiocb *aiocbp)}
+\fdesc{Richiede la cancellazione delle operazioni di I/O asincrono.} 
+}
+
+{La funzione ritorna un intero positivo che indica il risultato
+  dell'operazione in caso di successo e $-1$ per un errore, nel qual caso
+  \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+  \item[\errcode{EBADF}] \param{fd} non è un file descriptor valido.
+  \item[\errcode{ENOSYS}] la funzione non è implementata.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione permette di cancellare una operazione specifica sul file
+\param{fd}, idicata con \param{aiocbp}, o tutte le operazioni pendenti,
+specificando \val{NULL} come valore di \param{aiocbp}. Quando una operazione
+viene cancellata una successiva chiamata ad \func{aio\_error} riporterà
+\errcode{ECANCELED} come codice di errore, ed mentre il valore di ritorno per
+\func{aio\_return} sarà $-1$, inoltre il meccanismo di notifica non verrà
+invocato. Se con \param{aiocbp} si specifica una operazione relativa ad un
+file descriptor diverso da \param{fd} il risultato è indeterminato.  In caso
+di successo, i possibili valori di ritorno per \func{aio\_cancel} (anch'essi
+definiti in \headfile{aio.h}) sono tre:
+\begin{basedescript}{\desclabelwidth{3.0cm}}
+\item[\const{AIO\_ALLDONE}] indica che le operazioni di cui si è richiesta la
+  cancellazione sono state già completate,
+  
+\item[\const{AIO\_CANCELED}] indica che tutte le operazioni richieste sono
+  state cancellate,  
+  
+\item[\const{AIO\_NOTCANCELED}] indica che alcune delle operazioni erano in
+  corso e non sono state cancellate.
+\end{basedescript}
+
+Nel caso si abbia \const{AIO\_NOTCANCELED} occorrerà chiamare
+\func{aio\_error} per determinare quali sono le operazioni effettivamente
+cancellate. Le operazioni che non sono state cancellate proseguiranno il loro
+corso normale, compreso quanto richiesto riguardo al meccanismo di notifica
+del loro avvenuto completamento.
+
+Benché l'I/O asincrono preveda un meccanismo di notifica, l'interfaccia
+fornisce anche una apposita funzione, \funcd{aio\_suspend}, che permette di
+sospendere l'esecuzione del processo chiamante fino al completamento di una
+specifica operazione; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int aio\_suspend(const struct aiocb * const list[], int nent, \\
+\phantom{int aio\_suspend(}const struct timespec *timeout)}
+\fdesc{Attende il completamento di una operazione di I/O asincrono.} 
+}
+
+{La funzione ritorna $0$ se una (o più) operazioni sono state completate e
+  $-1$ per un errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+    \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
+      \param{timeout}.
+    \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+    \item[\errcode{ENOSYS}] la funzione non è implementata.
+  \end{errlist}
+}
+\end{funcproto}
+  
+La funzione permette di bloccare il processo fintanto che almeno una delle
+\param{nent} operazioni specificate nella lista \param{list} è completata, per
+un tempo massimo specificato dalla struttura \struct{timespec} puntata
+da \param{timout}, o fintanto che non arrivi un segnale (si tenga conto che
+questo segnale potrebbe essere anche quello utilizzato come meccanismo di
+notifica). La lista deve essere inizializzata con delle strutture
+\struct{aiocb} relative ad operazioni effettivamente richieste, ma può
+contenere puntatori nulli, che saranno ignorati. In caso si siano specificati
+valori non validi l'effetto è indefinito.  
+Un valore \val{NULL} per \param{timout} comporta l'assenza di timeout, mentre
+se si vuole effettuare un \textit{polling} sulle operazioni occorrerà
+specificare un puntatore valido ad una struttura \texttt{timespec} (vedi
+fig.~\ref{fig:sys_timespec_struct}) contenente valori nulli, e verificare poi
+con \func{aio\_error} quale delle operazioni della lista \param{list} è stata
+completata.
 
-In tal caso il sistema genera un segnale \macro{SIGIO} tutte le volte che sono
-presenti dei dati in input su un file aperto in questa modalità.  Uno dei
-problemi che si presentavano con le prime implementazioni di questa modalità
-di I/O è che essa poteva essere usata in maniera semplice aprendo un solo file
-per processo, dato che altrimenti si sarebbe dovuto provvedere ad effettuare
-una serie di controlli su tutti i file aperti per distinguere a quale fosse
-dovuto l'emissione del segnale.
+Lo standard POSIX.1b infine ha previsto pure una funzione, \funcd{lio\_listio},
+che permette di effettuare la richiesta di una intera lista di operazioni di
+lettura o scrittura; il suo prototipo è:
 
-Tutto questo adesso può essere evitato facendo ricorso alle informazioni
-restituite al manipolatore del segnale attraverso la struttura
-\var{siginfo\_t} (vedi \figref{fig:sig_siginfo_t}), il cui campo \var{si\_fd}
-riporta il file descriptor che ha generato il segnale.
 
+\begin{funcproto}{
+\fhead{aio.h}
+\fdecl{int lio\_listio(int mode, struct aiocb * const list[], int nent, struct
+    sigevent *sig)}
+
+\fdesc{Richiede l'esecuzione di una serie di operazioni di I/O.} 
+}
+
+{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{EAGAIN}] nessuna operazione è stata completata entro
+      \param{timeout}.
+    \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+    \item[\errcode{EINVAL}] si è passato un valore di \param{mode} non valido
+      o un numero di operazioni \param{nent} maggiore di
+      \const{AIO\_LISTIO\_MAX}.
+    \item[\errcode{ENOSYS}] la funzione non è implementata.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione esegue la richiesta delle \param{nent} operazioni indicate nella
+lista \param{list} un vettore di puntatori a strutture \struct{aiocb}
+indicanti le operazioni da compiere (che verranno eseguite senza un ordine
+particolare). La lista può contenere anche puntatori nulli, che saranno
+ignorati (si possono così eliminare facilmente componenti della lista senza
+doverla rigenerare).
+
+Ciascuna struttura \struct{aiocb} della lista deve contenere un
+\textit{control block} opportunamente inizializzato; in particolare per
+ognuna di esse dovrà essere specificato il tipo di operazione con il campo
+\var{aio\_lio\_opcode}, che può prendere i valori:
+\begin{basedescript}{\desclabelwidth{2.0cm}}
+\item[\const{LIO\_READ}]  si richiede una operazione di lettura.
+\item[\const{LIO\_WRITE}] si richiede una operazione di scrittura.
+na operazione.
+\end{basedescript}
+dove \const{LIO\_NOP} viene usato quando si ha a che fare con un vettore di
+dimensione fissa, per poter specificare solo alcune operazioni, o quando si
+sono dovute cancellare delle operazioni e si deve ripetere la richiesta per
+quelle non completate. 
+
+L'argomento \param{mode} controlla il comportamento della funzione, se viene
+usato il valore \const{LIO\_WAIT} la funzione si blocca fino al completamento
+di tutte le operazioni richieste; se si usa \const{LIO\_NOWAIT} la funzione
+ritorna immediatamente dopo aver messo in coda tutte le richieste. In tal caso
+il chiamante può richiedere la notifica del completamento di tutte le
+richieste, impostando l'argomento \param{sig} in maniera analoga a come si fa
+per il campo \var{aio\_sigevent} di \struct{aiocb}.
+
+% TODO: trattare libaio e le system call del kernel per l'I/O asincrono, vedi
+% http://lse.sourceforge.net/io/aio.html,
+% http://webfiveoh.com/content/guides/2012/aug/mon-13th/linux-asynchronous-io-and-libaio.html, 
+% https://code.google.com/p/kernel/wiki/AIOUserGuide,
+% http://bert-hubert.blogspot.de/2012/05/on-linux-asynchronous-file-io.html 
+
+
+\section{Altre modalità di I/O avanzato}
+\label{sec:file_advanced_io}
+
+Oltre alle precedenti modalità di \textit{I/O multiplexing} e \textsl{I/O
+  asincrono}, esistono altre funzioni che implementano delle modalità di
+accesso ai file più evolute rispetto alle normali funzioni di lettura e
+scrittura che abbiamo esaminato in sez.~\ref{sec:file_unix_interface}. In
+questa sezione allora prenderemo in esame le interfacce per l'\textsl{I/O
+  mappato in memoria}, per l'\textsl{I/O vettorizzato} e altre funzioni di I/O
+avanzato.
 
 
 \subsection{File mappati in memoria}
 \label{sec:file_memory_map}
 
+\itindbeg{memory~mapping}
+Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
+rispetto a quella classica vista in sez.~\ref{sec:file_unix_interface}, è il
+cosiddetto \textit{memory-mapped I/O}, che attraverso il meccanismo della
+\textsl{paginazione} \index{paginazione} usato dalla memoria virtuale (vedi
+sez.~\ref{sec:proc_mem_gen}) permette di \textsl{mappare} il contenuto di un
+file in una sezione dello spazio di indirizzi del processo che lo ha allocato.
 
-\subsection{I/O multiplo}
-\label{sec:file_multiple_io}
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=12cm]{img/mmap_layout}
+  \caption{Disposizione della memoria di un processo quando si esegue la
+  mappatura in memoria di un file.}
+  \label{fig:file_mmap_layout}
+\end{figure}
 
+Il meccanismo è illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del
+file viene \textsl{mappata} direttamente nello spazio degli indirizzi del
+programma.  Tutte le operazioni di lettura e scrittura su variabili contenute
+in questa zona di memoria verranno eseguite leggendo e scrivendo dal contenuto
+del file attraverso il sistema della memoria virtuale illustrato in
+sez.~\ref{sec:proc_mem_gen} che in maniera analoga a quanto avviene per le
+pagine che vengono salvate e rilette nella \textit{swap}, si incaricherà di
+sincronizzare il contenuto di quel segmento di memoria con quello del file
+mappato su di esso.  Per questo motivo si può parlare tanto di \textsl{file
+  mappato in memoria}, quanto di \textsl{memoria mappata su file}.
 
+L'uso del \textit{memory-mapping} comporta una notevole semplificazione delle
+operazioni di I/O, in quanto non sarà più necessario utilizzare dei buffer
+intermedi su cui appoggiare i dati da traferire, poiché questi potranno essere
+acceduti direttamente nella sezione di memoria mappata; inoltre questa
+interfaccia è più efficiente delle usuali funzioni di I/O, in quanto permette
+di caricare in memoria solo le parti del file che sono effettivamente usate ad
+un dato istante.
 
-\section{Il file locking}
-\label{sec:file_locking}
+Infatti, dato che l'accesso è fatto direttamente attraverso la memoria
+virtuale, la sezione di memoria mappata su cui si opera sarà a sua volta letta
+o scritta sul file una pagina alla volta e solo per le parti effettivamente
+usate, il tutto in maniera completamente trasparente al processo; l'accesso
+alle pagine non ancora caricate avverrà allo stesso modo con cui vengono
+caricate in memoria le pagine che sono state salvate sullo \textit{swap}.
 
-In \secref{sec:file_sharing} abbiamo preso in esame le modalità in cui un
-sistema unix-like gestisce la condivisione dei file da parte di processi
-diversi. In quell'occasione si è visto come, con l'eccezione dei file aperti
-in \textit{append mode}, quando più processi scrivono contemporaneamente sullo
-stesso file non è possibile determinare la sequenza in cui essi opereranno.
+Infine in situazioni in cui la memoria è scarsa, le pagine che mappano un file
+vengono salvate automaticamente, così come le pagine dei programmi vengono
+scritte sulla \textit{swap}; questo consente di accedere ai file su dimensioni
+il cui solo limite è quello dello spazio di indirizzi disponibile, e non della
+memoria su cui possono esserne lette delle porzioni.
 
-Questo causa la possibilità di race condition\index{race condition}; in
-generale le situazioni più comuni sono due: l'interazione fra un processo che
-scrive e altri che leggono, in cui questi ultimi possono leggere informazioni
-scritte solo in maniera parziale o incompleta; o quella in cui diversi
-processi scrivono, mescolando in maniera imprevedibile il loro output sul
+L'interfaccia POSIX implementata da Linux prevede varie funzioni di sistema
+per la gestione del \textit{memory mapped I/O}, la prima di queste, che serve
+ad eseguire la mappatura in memoria di un file, è \funcd{mmap}; il suo
+prototipo è:
+
+\begin{funcproto}{
+%\fhead{unistd.h}
+\fhead{sys/mman.h} 
+\fdecl{void * mmap(void * start, size\_t length, int prot, int flags, int
+    fd, off\_t offset)}
+\fdesc{Esegue la mappatura in memoria di una sezione di un file.} 
+}
+
+{La funzione ritorna il puntatore alla zona di memoria mappata in caso di
+  successo, e \const{MAP\_FAILED} (\texttt{(void *) -1}) per un errore, nel
+  qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+    \item[\errcode{EACCES}] o \param{fd} non si riferisce ad un file regolare,
+      o si è usato \const{MAP\_PRIVATE} ma \param{fd} non è aperto in lettura,
+      o si è usato \const{MAP\_SHARED} e impostato \const{PROT\_WRITE} ed
+      \param{fd} non è aperto in lettura/scrittura, o si è impostato
+      \const{PROT\_WRITE} ed \param{fd} è in \textit{append-only}.
+    \item[\errcode{EAGAIN}] il file è bloccato, o si è bloccata troppa memoria
+      rispetto a quanto consentito dai limiti di sistema (vedi
+      sez.~\ref{sec:sys_resource_limit}).
+    \item[\errcode{EBADF}] il file descriptor non è valido, e non si è usato
+      \const{MAP\_ANONYMOUS}.
+    \item[\errcode{EINVAL}] i valori di \param{start}, \param{length} o
+      \param{offset} non sono validi (o troppo grandi o non allineati sulla
+      dimensione delle pagine), o \param{lengh} è zero (solo dal 2.6.12)
+      o \param{flags} contiene sia \const{MAP\_PRIVATE} che
+      \const{MAP\_SHARED} o nessuno dei due.
+    \item[\errcode{ENFILE}] si è superato il limite del sistema sul numero di
+      file aperti (vedi sez.~\ref{sec:sys_resource_limit}).
+    \item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory
+      mapping.
+    \item[\errcode{ENOMEM}] non c'è memoria o si è superato il limite sul
+      numero di mappature possibili.
+    \item[\errcode{EOVERFLOW}] su architettura a 32 bit con il supporto per i
+      \textit{large file} (che hanno una dimensione a 64 bit) il numero di
+      pagine usato per \param{lenght} aggiunto a quello usato
+      per \param{offset} eccede i 32 bit (\texttt{unsigned long}).
+    \item[\errcode{EPERM}] l'argomento \param{prot} ha richiesto
+      \const{PROT\_EXEC}, ma il filesystem di \param{fd} è montato con
+      l'opzione \texttt{noexec}.
+    \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma
+      \param{fd} è aperto in scrittura.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione richiede di mappare in memoria la sezione del file \param{fd} a
+partire da \param{offset} per \param{length} byte, preferibilmente
+all'indirizzo \param{start}. Il valore \param{start} viene normalmente
+considerato come un suggerimento, ma l'uso di un qualunque valore diverso da
+\val{NULL}, in cui si rimette completamente al kernel la scelta
+dell'indirizzo, viene sconsigliato per ragioni di portabilità. Il valore
+di \param{offset} deve essere un multiplo della dimensione di una pagina di
+memoria.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{PROT\_EXEC}  & Le pagine possono essere eseguite.\\
+    \const{PROT\_READ}  & Le pagine possono essere lette.\\
+    \const{PROT\_WRITE} & Le pagine possono essere scritte.\\
+    \const{PROT\_NONE}  & L'accesso alle pagine è vietato.\\
+    \hline    
+  \end{tabular}
+  \caption{Valori dell'argomento \param{prot} di \func{mmap}, relativi alla
+    protezione applicate alle pagine del file mappate in memoria.}
+  \label{tab:file_mmap_prot}
+\end{table}
+
+Il valore dell'argomento \param{prot} indica la protezione\footnote{come
+  accennato in sez.~\ref{sec:proc_memory} in Linux la memoria reale è divisa
+  in pagine, ogni processo vede la sua memoria attraverso uno o più segmenti
+  lineari di memoria virtuale; per ciascuno di questi segmenti il kernel
+  mantiene nella \textit{page table} la mappatura sulle pagine di memoria
+  reale, ed le modalità di accesso (lettura, esecuzione, scrittura); una loro
+  violazione causa quella una \textit{segment violation}, e la relativa
+  emissione del segnale \signal{SIGSEGV}.} da applicare al segmento di memoria
+e deve essere specificato come maschera binaria ottenuta dall'OR di uno o più
+dei valori riportati in tab.~\ref{tab:file_mmap_prot}; il valore specificato
+deve essere compatibile con la modalità di accesso con cui si è aperto il
 file.
 
-In tutti questi casi il \textit{file locking} è la tecnica che permette di
-evitare le race condition, attraverso una serie di funzioni che permettono di
-bloccare l'accesso al file da parte di altri processi, così da evitare le
-sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
+\begin{table}[!htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{11cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{MAP\_32BIT}     & Esegue la mappatura sui primi 2Gb dello spazio
+                             degli indirizzi, viene supportato solo sulle
+                             piattaforme \texttt{x86-64} per compatibilità con
+                             le applicazioni a 32 bit. Viene ignorato se si è
+                             richiesto \const{MAP\_FIXED} (dal kernel 2.4.20).\\
+    \const{MAP\_ANON}      & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\
+    \const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
+                             argomenti \param{fd} e \param{offset} sono
+                             ignorati. L'uso di questo flag con
+                             \const{MAP\_SHARED} è stato implementato in Linux
+                             a partire dai kernel della serie 2.4.x.\\
+    \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
+                             \textit{DoS}
+                             (veniva usato per segnalare che tentativi di
+                             scrittura sul file dovevano fallire con
+                             \errcode{ETXTBSY}).\\ 
+    \const{MAP\_EXECUTABLE}& Ignorato.\\
+    \const{MAP\_FILE}      & Valore di compatibilità, ignorato.\\
+    \const{MAP\_FIXED}     & Non permette di restituire un indirizzo diverso
+                             da \param{start}, se questo non può essere usato
+                             \func{mmap} fallisce. Se si imposta questo flag il
+                             valore di \param{start} deve essere allineato
+                             alle dimensioni di una pagina.\\
+    \const{MAP\_GROWSDOWN} & Usato per gli \textit{stack}. 
+                             Indica che la mappatura deve essere effettuata 
+                             con gli indirizzi crescenti verso il basso.\\
+    \const{MAP\_HUGETLB}   & Esegue la mappatura usando le cosiddette
+                             ``\textit{huge pages}'' (dal kernel 2.6.32).\\
+    \const{MAP\_LOCKED}    & Se impostato impedisce lo \textit{swapping} delle
+                             pagine mappate (dal kernel 2.5.37).\\
+    \const{MAP\_NONBLOCK}  & Esegue un \textit{prefaulting} più limitato che
+                             non causa I/O (dal kernel 2.5.46).\\
+    \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
+                             delle pagine di \textit{swap} ad uso del meccanismo
+                             del \textit{copy on write} 
+                             per mantenere le modifiche fatte alla regione
+                             mappata, in questo caso dopo una scrittura, se
+                             non c'è più memoria disponibile, si ha
+                             l'emissione di un \signal{SIGSEGV}.\\
+    \const{MAP\_POPULATE}  & Esegue il \textit{prefaulting} delle pagine di
+                             memoria necessarie alla mappatura (dal kernel
+                             2.5.46).\\ 
+    \const{MAP\_PRIVATE}   & I cambiamenti sulla memoria mappata non vengono
+                             riportati sul file. Ne viene fatta una copia
+                             privata cui solo il processo chiamante ha
+                             accesso.  Incompatibile con \const{MAP\_SHARED}.\\
+    \const{MAP\_SHARED}    & I cambiamenti sulla memoria mappata vengono
+                             riportati sul file e saranno immediatamente
+                             visibili agli altri processi che mappano lo stesso
+                             file. Incompatibile
+                             con \const{MAP\_PRIVATE}.\\ 
+    \const{MAP\_STACK}     & Al momento è ignorato, è stato fornito (dal kernel
+                             2.6.27) a supporto della implementazione dei
+                             thread nelle \acr{glibc}, per allocare memoria in
+                             uno spazio utilizzabile come \textit{stack} per le
+                             architetture hardware che richiedono un
+                             trattamento speciale di quest'ultimo.\\
+    \const{MAP\_UNINITIALIZED}& Specifico per i sistemi embedded ed
+                             utilizzabile dal kernel 2.6.33 solo se è stata
+                             abilitata in fase di compilazione dello stesso
+                             l'opzione
+                             \texttt{CONFIG\_MMAP\_ALLOW\_UNINITIALIZED}. Se
+                             usato le pagine di memoria usate nella mappatura
+                             anonima non vengono cancellate; questo migliora
+                             le prestazioni sui sistemi con risorse minime, ma
+                             comporta la possibilità di rileggere i dati di
+                             altri processi che han chiuso una mappatura, per
+                             cui viene usato solo quando (come si suppone sia
+                             per i sistemi embedded) si ha il completo
+                             controllo dell'uso della memoria da parte degli
+                             utenti.\\ 
+%     \const{MAP\_DONTEXPAND}& Non consente una successiva espansione dell'area
+%                              mappata con \func{mremap}, proposto ma pare non
+%                              implementato.\\
+    \hline
+  \end{tabular}
+  \caption{Valori possibili dell'argomento \param{flag} di \func{mmap}.}
+  \label{tab:file_mmap_flag}
+\end{table}
+
+% TODO trattare MAP_HUGETLB introdotto con il kernel 2.6.32, e modifiche
+% introdotte con il 3.8 per le dimensioni variabili delle huge pages
+
+L'argomento \param{flags} specifica infine qual è il tipo di oggetto mappato,
+le opzioni relative alle modalità con cui è effettuata la mappatura e alle
+modalità con cui le modifiche alla memoria mappata vengono condivise o
+mantenute private al processo che le ha effettuate. Deve essere specificato
+come maschera binaria ottenuta dall'OR di uno o più dei valori riportati in
+tab.~\ref{tab:file_mmap_flag}. Fra questi comunque deve sempre essere
+specificato o \const{MAP\_PRIVATE} o \const{MAP\_SHARED} per indicare la
+modalità con cui viene effettuata la mappatura.
+
+Esistono infatti due modalità alternative di eseguire la mappatura di un file;
+la più comune è \const{MAP\_SHARED} in cui la memoria è condivisa e le
+modifiche effettuate su di essa sono visibili a tutti i processi che hanno
+mappato lo stesso file. In questo caso le modifiche vengono anche riportate su
+disco, anche se questo può non essere immediato a causa della bufferizzazione:
+si potrà essere sicuri dell'aggiornamento solo in seguito alla chiamata di
+\func{msync} o \func{munmap}, e solo allora le modifiche saranno visibili sul
+file con l'I/O convenzionale.
+
+Con \const{MAP\_PRIVATE} invece viene creata una copia privata del file,
+questo non viene mai modificato e solo il processo chiamante ha accesso alla
+mappatura. Le modifiche eseguite dal processo sulla mappatura vengono
+effettuate utilizzando il meccanismo del \textit{copy on write}, mentenute in
+memoria e salvate su \textit{swap} in caso di necessità.  Non è specificato se
+i cambiamenti sul file originale vengano riportati sulla regione mappata.
+
+Gli altri valori di \func{flag} modificano le caratteristiche della
+mappatura. Fra questi il più rilevante è probabilmente \const{MAP\_ANONYMOUS}
+che consente di creare segmenti di memoria condivisa fra processi diversi
+senza appoggiarsi a nessun file (torneremo sul suo utilizzo in
+sez.~\ref{sec:ipc_mmap_anonymous}). In tal caso gli argomenti \param{fd}
+e \param{offset} vangono ignorati, anche se alcune implementazioni richiedono
+che invece \param{fd} sia $-1$, convenzione che è opportuno seguire se si ha a
+cuore la portabilità dei programmi.
+
+Gli effetti dell'accesso ad una zona di memoria mappata su file possono essere
+piuttosto complessi, essi si possono comprendere solo tenendo presente che
+tutto quanto è comunque basato sul meccanismo della memoria virtuale. Questo
+comporta allora una serie di conseguenze. La più ovvia è che se si cerca di
+scrivere su una zona mappata in sola lettura si avrà l'emissione di un segnale
+di violazione di accesso (\signal{SIGSEGV}), dato che i permessi sul segmento
+di memoria relativo non consentono questo tipo di accesso.
+
+È invece assai diversa la questione relativa agli accessi al di fuori della
+regione di cui si è richiesta la mappatura. A prima vista infatti si potrebbe
+ritenere che anch'essi debbano generare un segnale di violazione di accesso;
+questo però non tiene conto del fatto che, essendo basata sul meccanismo della
+paginazione, la mappatura in memoria non può che essere eseguita su un
+segmento di dimensioni rigorosamente multiple di quelle di una pagina, ed in
+generale queste potranno non corrispondere alle dimensioni effettive del file
+o della sezione che si vuole mappare.
+
+\begin{figure}[!htb] 
+  \centering
+  \includegraphics[height=6cm]{img/mmap_boundary}
+  \caption{Schema della mappatura in memoria di una sezione di file di
+    dimensioni non corrispondenti al bordo di una pagina.}
+  \label{fig:file_mmap_boundary}
+\end{figure}
+
+Il caso più comune è quello illustrato in fig.~\ref{fig:file_mmap_boundary},
+in cui la sezione di file non rientra nei confini di una pagina: in tal caso
+il file sarà mappato su un segmento di memoria che si estende fino al
+bordo della pagina successiva.  In questo caso è possibile accedere a quella
+zona di memoria che eccede le dimensioni specificate da \param{length}, senza
+ottenere un \signal{SIGSEGV} poiché essa è presente nello spazio di indirizzi
+del processo, anche se non è mappata sul file. Il comportamento del sistema è
+quello di restituire un valore nullo per quanto viene letto, e di non
+riportare su file quanto viene scritto.
+
+Un caso più complesso è quello che si viene a creare quando le dimensioni del
+file mappato sono più corte delle dimensioni della mappatura, oppure quando il
+file è stato troncato, dopo che è stato mappato, ad una dimensione inferiore a
+quella della mappatura in memoria.  In questa situazione, per la sezione di
+pagina parzialmente coperta dal contenuto del file, vale esattamente quanto
+visto in precedenza; invece per la parte che eccede, fino alle dimensioni date
+da \param{length}, l'accesso non sarà più possibile, ma il segnale emesso non
+sarà \signal{SIGSEGV}, ma \signal{SIGBUS}, come illustrato in
+fig.~\ref{fig:file_mmap_exceed}.
+
+Non tutti i file possono venire mappati in memoria, dato che, come illustrato
+in fig.~\ref{fig:file_mmap_layout}, la mappatura introduce una corrispondenza
+biunivoca fra una sezione di un file ed una sezione di memoria. Questo
+comporta che ad esempio non è possibile mappare in memoria file descriptor
+relativi a \textit{pipe}, socket e \textit{fifo}, per i quali non ha senso
+parlare di \textsl{sezione}. Lo stesso vale anche per alcuni file di
+dispositivo, che non dispongono della relativa operazione \func{mmap} (si
+ricordi quanto esposto in sez.~\ref{sec:file_vfs_work}). Si tenga presente
+però che esistono anche casi di dispositivi (un esempio è l'interfaccia al
+ponte PCI-VME del chip Universe) che sono utilizzabili solo con questa
+interfaccia.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[height=6cm]{img/mmap_exceed}
+  \caption{Schema della mappatura in memoria di file di dimensioni inferiori
+    alla lunghezza richiesta.}
+  \label{fig:file_mmap_exceed}
+\end{figure}
+
+Dato che passando attraverso una \func{fork} lo spazio di indirizzi viene
+copiato integralmente, i file mappati in memoria verranno ereditati in maniera
+trasparente dal processo figlio, mantenendo gli stessi attributi avuti nel
+padre; così se si è usato \const{MAP\_SHARED} padre e figlio accederanno allo
+stesso file in maniera condivisa, mentre se si è usato \const{MAP\_PRIVATE}
+ciascuno di essi manterrà una sua versione privata indipendente. Non c'è
+invece nessun passaggio attraverso una \func{exec}, dato che quest'ultima
+sostituisce tutto lo spazio degli indirizzi di un processo con quello di un
+nuovo programma.
+
+Quando si effettua la mappatura di un file vengono pure modificati i tempi ad
+esso associati (di cui si è trattato in sez.~\ref{sec:file_file_times}). Il
+valore di \var{st\_atime} può venir cambiato in qualunque istante a partire
+dal momento in cui la mappatura è stata effettuata: il primo riferimento ad
+una pagina mappata su un file aggiorna questo tempo.  I valori di
+\var{st\_ctime} e \var{st\_mtime} possono venir cambiati solo quando si è
+consentita la scrittura sul file (cioè per un file mappato con
+\const{PROT\_WRITE} e \const{MAP\_SHARED}) e sono aggiornati dopo la scrittura
+o in corrispondenza di una eventuale \func{msync}.
+
+Dato per i file mappati in memoria le operazioni di I/O sono gestite
+direttamente dalla memoria virtuale, occorre essere consapevoli delle
+interazioni che possono esserci con operazioni effettuate con l'interfaccia
+dei file ordinaria illustrata in sez.~\ref{sec:file_unix_interface}. Il
+problema è che una volta che si è mappato un file, le operazioni di lettura e
+scrittura saranno eseguite sulla memoria, e riportate su disco in maniera
+autonoma dal sistema della memoria virtuale.
+
+Pertanto se si modifica un file con l'interfaccia ordinaria queste modifiche
+potranno essere visibili o meno a seconda del momento in cui la memoria
+virtuale trasporterà dal disco in memoria quella sezione del file, perciò è
+del tutto imprevedibile il risultato della modifica di un file nei confronti
+del contenuto della memoria su cui è mappato.
+
+Per questo è sempre sconsigliabile eseguire scritture su un file attraverso
+l'interfaccia ordinaria quando lo si è mappato in memoria, è invece possibile
+usare l'interfaccia ordinaria per leggere un file mappato in memoria, purché
+si abbia una certa cura; infatti l'interfaccia dell'I/O mappato in memoria
+mette a disposizione la funzione \funcd{msync} per sincronizzare il contenuto
+della memoria mappata con il file su disco; il suo prototipo è:
+
+\begin{funcproto}{
+%\fhead{unistd.h}
+\fhead{sys/mman.h}
+\fdecl{int msync(const void *start, size\_t length, int flags)}
+\fdesc{Sincronizza i contenuti di una sezione di un file mappato in memoria.} 
+}
+
+{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{EBUSY}] si è indicato \const{MS\_INVALIDATE} ma
+      nell'intervallo di memoria specificato è presente un \textit{memory lock}.
+    \item[\errcode{EFAULT}] l'intervallo indicato, o parte di esso, non
+      risulta mappato (prima del kernel 2.4.19).
+    \item[\errcode{EINVAL}] o \param{start} non è multiplo di
+      \const{PAGE\_SIZE}, o si è specificato un valore non valido per
+      \param{flags}.
+    \item[\errcode{ENOMEM}] l'intervallo indicato, o parte di esso, non
+      risulta mappato (dal kernel 2.4.19).
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione esegue la sincronizzazione di quanto scritto nella sezione di
+memoria indicata da \param{start} e \param{offset}, scrivendo le modifiche sul
+file (qualora questo non sia già stato fatto).  Provvede anche ad aggiornare i
+relativi tempi di modifica. In questo modo si è sicuri che dopo l'esecuzione
+di \func{msync} le funzioni dell'interfaccia ordinaria troveranno un contenuto
+del file aggiornato.
+
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{11cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{MS\_SYNC}       & richiede una sincronizzazione e ritorna soltanto
+                             quando questa è stata completata.\\
+    \const{MS\_ASYNC}      & richiede una sincronizzazione, ma ritorna subito 
+                             non attendendo che questa sia finita.\\
+    \const{MS\_INVALIDATE} & invalida le pagine per tutte le mappature
+                             in memoria così da rendere necessaria una
+                             rilettura immediata delle stesse.\\
+    \hline
+  \end{tabular}
+  \caption{Valori possibili dell'argomento \param{flag} di \func{msync}.}
+  \label{tab:file_mmap_msync}
+\end{table}
+
+L'argomento \param{flag} è specificato come maschera binaria composta da un OR
+dei valori riportati in tab.~\ref{tab:file_mmap_msync}, di questi però
+\const{MS\_ASYNC} e \const{MS\_SYNC} sono incompatibili; con il primo valore
+infatti la funzione si limita ad inoltrare la richiesta di sincronizzazione al
+meccanismo della memoria virtuale, ritornando subito, mentre con il secondo
+attende che la sincronizzazione sia stata effettivamente eseguita. Il terzo
+valore fa sì che vengano invalidate, per tutte le mappature dello stesso file,
+le pagine di cui si è richiesta la sincronizzazione, così che esse possano
+essere immediatamente aggiornate con i nuovi valori.
+
+Una volta che si sono completate le operazioni di I/O si può eliminare la
+mappatura della memoria usando la funzione \funcd{munmap}, il suo prototipo è:
+
+\begin{funcproto}{
+%\fhead{unistd.h}
+\fhead{sys/mman.h}
+\fdecl{int munmap(void *start, size\_t length)}
+\fdesc{Rilascia la mappatura sulla sezione di memoria specificata.} 
+}
+
+{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{EINVAL}] l'intervallo specificato non ricade in una zona
+      precedentemente mappata.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione cancella la mappatura per l'intervallo specificato con
+\param{start} e \param{length}; ogni successivo accesso a tale regione causerà
+un errore di accesso in memoria. L'argomento \param{start} deve essere
+allineato alle dimensioni di una pagina, e la mappatura di tutte le pagine
+contenute anche parzialmente nell'intervallo indicato, verrà rimossa.
+Indicare un intervallo che non contiene mappature non è un errore.  Si tenga
+presente inoltre che alla conclusione di un processo ogni pagina mappata verrà
+automaticamente rilasciata, mentre la chiusura del file descriptor usato per
+il \textit{memory mapping} non ha alcun effetto su di esso.
+
+Lo standard POSIX prevede anche una funzione che permetta di cambiare le
+protezioni delle pagine di memoria; lo standard prevede che essa si applichi
+solo ai \textit{memory mapping} creati con \func{mmap}, ma nel caso di Linux
+la funzione può essere usata con qualunque pagina valida nella memoria
+virtuale. Questa funzione di sistema è \funcd{mprotect} ed il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h} 
+\fdecl{int mprotect(const void *addr, size\_t len, int prot)}
+\fdesc{Modifica le protezioni delle pagine di memoria.} 
+}
+
+{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{EINVAL}] il valore di \param{addr} non è valido o non è un
+      multiplo di \const{PAGE\_SIZE}.
+    \item[\errcode{EACCES}] l'operazione non è consentita, ad esempio si è
+      cercato di marcare con \const{PROT\_WRITE} un segmento di memoria cui si
+      ha solo accesso in lettura.
+    \item[\errcode{ENOMEM}] non è stato possibile allocare le risorse
+      necessarie all'interno del kernel o si è specificato un indirizzo di
+      memoria non valido del processo o non corrispondente a pagine mappate
+      (negli ultimi due casi prima del kernel 2.4.19 veniva prodotto,
+      erroneamente, \errcode{EFAULT}).
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione prende come argomenti un indirizzo di partenza in \param{addr},
+allineato alle dimensioni delle pagine di memoria, ed una dimensione
+\param{size}. La nuova protezione deve essere specificata in \param{prot} con
+una combinazione dei valori di tab.~\ref{tab:file_mmap_prot}.  La nuova
+protezione verrà applicata a tutte le pagine contenute, anche parzialmente,
+dall'intervallo fra \param{addr} e \param{addr}+\param{size}-1.
+
+Infine Linux supporta alcune operazioni specifiche non disponibili su altri
+kernel unix-like per poter usare le quali occorre però dichiarare
+\macro{\_GNU\_SOURCE} prima dell'inclusione di \texttt{sys/mman.h}. La prima
+di queste è la possibilità di modificare un precedente \textit{memory
+  mapping}, ad esempio per espanderlo o restringerlo.  Questo è realizzato
+dalla funzione di sistema \funcd{mremap}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h} 
+\fdecl{void * mremap(void *old\_address, size\_t old\_size , size\_t
+    new\_size, unsigned long flags)}
+\fdesc{Restringe o allarga una mappatura in memoria.} 
+}
+
+{La funzione ritorna l'indirizzo alla nuova area di memoria in caso di
+  successo o il valore \const{MAP\_FAILED} (pari a \texttt{(void *) -1}), nel
+  qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+    \item[\errcode{EINVAL}] il valore di \param{old\_address} non è un
+      puntatore valido.
+    \item[\errcode{EFAULT}] ci sono indirizzi non validi nell'intervallo
+      specificato da \param{old\_address} e \param{old\_size}, o ci sono altre
+      mappature di tipo non corrispondente a quella richiesta.
+    \item[\errcode{ENOMEM}] non c'è memoria sufficiente oppure l'area di
+      memoria non può essere espansa all'indirizzo virtuale corrente, e non si
+      è specificato \const{MREMAP\_MAYMOVE} nei flag.
+    \item[\errcode{EAGAIN}] il segmento di memoria scelto è bloccato e non può
+      essere rimappato.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione richiede come argomenti \param{old\_address} (che deve essere
+allineato alle dimensioni di una pagina di memoria) che specifica il
+precedente indirizzo del \textit{memory mapping} e \param{old\_size}, che ne
+indica la dimensione. Con \param{new\_size} si specifica invece la nuova
+dimensione che si vuole ottenere. Infine l'argomento \param{flags} è una
+maschera binaria per i flag che controllano il comportamento della funzione.
+Il solo valore utilizzato è \const{MREMAP\_MAYMOVE} che consente di eseguire
+l'espansione anche quando non è possibile utilizzare il precedente
+indirizzo. Per questo motivo, se si è usato questo flag, la funzione può
+restituire un indirizzo della nuova zona di memoria che non è detto coincida
+con \param{old\_address}.
+
+La funzione si appoggia al sistema della memoria virtuale per modificare
+l'associazione fra gli indirizzi virtuali del processo e le pagine di memoria,
+modificando i dati direttamente nella \textit{page table} del processo. Come
+per \func{mprotect} la funzione può essere usata in generale, anche per pagine
+di memoria non corrispondenti ad un \textit{memory mapping}, e consente così
+di implementare la funzione \func{realloc} in maniera molto efficiente.
+
+Una caratteristica comune a tutti i sistemi unix-like è che la mappatura in
+memoria di un file viene eseguita in maniera lineare, cioè parti successive di
+un file vengono mappate linearmente su indirizzi successivi in memoria.
+Esistono però delle applicazioni (in particolare la tecnica è usata dai
+database o dai programmi che realizzano macchine virtuali) in cui è utile
+poter mappare sezioni diverse di un file su diverse zone di memoria.
+
+Questo è ovviamente sempre possibile eseguendo ripetutamente la funzione
+\func{mmap} per ciascuna delle diverse aree del file che si vogliono mappare
+in sequenza non lineare (ed in effetti è quello che veniva fatto anche con
+Linux prima che fossero introdotte queste estensioni) ma questo approccio ha
+delle conseguenze molto pesanti in termini di prestazioni.  Infatti per
+ciascuna mappatura in memoria deve essere definita nella \textit{page table}
+del processo una nuova area di memoria virtuale, quella che nel gergo del
+kernel viene chiamata VMA (\textit{virtual memory area}, che corrisponda alla
+mappatura, in modo che questa diventi visibile nello spazio degli indirizzi
+come illustrato in fig.~\ref{fig:file_mmap_layout}.
+
+Quando un processo esegue un gran numero di mappature diverse (si può arrivare
+anche a centinaia di migliaia) per realizzare a mano una mappatura non-lineare
+esso vedrà un accrescimento eccessivo della sua \textit{page table}, e lo
+stesso accadrà per tutti gli altri processi che utilizzano questa tecnica. In
+situazioni in cui le applicazioni hanno queste esigenze si avranno delle
+prestazioni ridotte, dato che il kernel dovrà impiegare molte risorse per
+mantenere i dati relativi al \textit{memory mapping}, sia in termini di
+memoria interna per i dati delle \textit{page table}, che di CPU per il loro
+aggiornamento.
+
+Per questo motivo con il kernel 2.5.46 è stato introdotto, ad opera di Ingo
+Molnar, un meccanismo che consente la mappatura non-lineare. Anche questa è
+una caratteristica specifica di Linux, non presente in altri sistemi
+unix-like.  Diventa così possibile utilizzare una sola mappatura iniziale, e
+quindi una sola \textit{virtual memory area} nella \textit{page table} del
+processo, e poi rimappare a piacere all'interno di questa i dati del file. Ciò
+è possibile grazie ad una nuova \textit{system call},
+\funcd{remap\_file\_pages}, il cui prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h} 
+\fdecl{int remap\_file\_pages(void *start, size\_t size, int prot,
+    ssize\_t pgoff, int flags)}
+\fdesc{Rimappa non linearmente un \textit{memory mapping}.} 
+}
+
+{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{EINVAL}] si è usato un valore non valido per uno degli
+      argomenti o \param{start} non fa riferimento ad un \textit{memory
+        mapping} valido creato con \const{MAP\_SHARED}.
+  \end{errlist}
+  ed inoltre 
+ nel loro significato generico.}
+\end{funcproto}
+
+Per poter utilizzare questa funzione occorre anzitutto effettuare
+preliminarmente una chiamata a \func{mmap} con \const{MAP\_SHARED} per
+definire l'area di memoria che poi sarà rimappata non linearmente. Poi si
+chiamerà questa funzione per modificare le corrispondenze fra pagine di
+memoria e pagine del file; si tenga presente che \func{remap\_file\_pages}
+permette anche di mappare la stessa pagina di un file in più pagine della
+regione mappata.
+
+La funzione richiede che si identifichi la sezione del file che si vuole
+riposizionare all'interno del \textit{memory mapping} con gli argomenti
+\param{pgoff} e \param{size}; l'argomento \param{start} invece deve indicare
+un indirizzo all'interno dell'area definita dall'\func{mmap} iniziale, a
+partire dal quale la sezione di file indicata verrà rimappata. L'argomento
+\param{prot} deve essere sempre nullo, mentre \param{flags} prende gli stessi
+valori di \func{mmap} (quelli di tab.~\ref{tab:file_mmap_prot}) ma di tutti i
+flag solo \const{MAP\_NONBLOCK} non viene ignorato.
+
+\itindbeg{prefaulting} 
+
+Insieme alla funzione \func{remap\_file\_pages} nel kernel 2.5.46 con sono
+stati introdotti anche due nuovi flag per \func{mmap}: \const{MAP\_POPULATE} e
+\const{MAP\_NONBLOCK}.  Il primo dei due consente di abilitare il meccanismo
+del \textit{prefaulting}. Questo viene di nuovo in aiuto per migliorare le
+prestazioni in certe condizioni di utilizzo del \textit{memory mapping}.
+
+Il problema si pone tutte le volte che si vuole mappare in memoria un file di
+grosse dimensioni. Il comportamento normale del sistema della memoria virtuale
+è quello per cui la regione mappata viene aggiunta alla \textit{page table}
+del processo, ma i dati verranno effettivamente utilizzati (si avrà cioè un
+\textit{page fault} che li trasferisce dal disco alla memoria) soltanto in
+corrispondenza dell'accesso a ciascuna delle pagine interessate dal
+\textit{memory mapping}.
+
+Questo vuol dire che il passaggio dei dati dal disco alla memoria avverrà una
+pagina alla volta con un gran numero di \textit{page fault}, chiaramente se si
+sa in anticipo che il file verrà utilizzato immediatamente, è molto più
+efficiente eseguire un \textit{prefaulting} in cui tutte le pagine di memoria
+interessate alla mappatura vengono ``\textsl{popolate}'' in una sola volta,
+questo comportamento viene abilitato quando si usa con \func{mmap} il flag
+\const{MAP\_POPULATE}.
+
+Dato che l'uso di \const{MAP\_POPULATE} comporta dell'I/O su disco che può
+rallentare l'esecuzione di \func{mmap} è stato introdotto anche un secondo
+flag, \const{MAP\_NONBLOCK}, che esegue un \textit{prefaulting} più limitato
+in cui vengono popolate solo le pagine della mappatura che già si trovano
+nella cache del kernel.\footnote{questo può essere utile per il linker
+  dinamico, in particolare quando viene effettuato il \textit{prelink} delle
+  applicazioni.}
+
+\itindend{prefaulting}
+
+Per i vantaggi illustrati all'inizio del paragrafo l'interfaccia del
+\textit{memory mapped I/O} viene usata da una grande varietà di programmi,
+spesso con esigenze molto diverse fra di loro riguardo le modalità con cui
+verranno eseguiti gli accessi ad un file; è ad esempio molto comune per i
+database effettuare accessi ai dati in maniera pressoché casuale, mentre un
+riproduttore audio o video eseguirà per lo più letture sequenziali.
+
+\itindend{memory~mapping}
+
+Per migliorare le prestazioni a seconda di queste modalità di accesso è
+disponibile una apposita funzione, \funcd{madvise},\footnote{tratteremo in
+  sez.~\ref{sec:file_fadvise} le funzioni che consentono di ottimizzare
+  l'accesso ai file con l'interfaccia classica.} che consente di fornire al
+kernel delle indicazioni su come un processo intende accedere ad un segmento
+di memoria, anche al di là delle mappature dei file, così che possano essere
+adottate le opportune strategie di ottimizzazione. Il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h}
+\fdecl{int madvise(void *start, size\_t length, int advice)}
+\fdesc{Fornisce indicazioni sull'uso previsto di un segmento di memoria.} 
+}
+
+{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}] la mappatura esiste ma non corrisponde ad un file.
+    \item[\errcode{EINVAL}] \param{start} non è allineato alla dimensione di
+      una pagina, \param{length} ha un valore negativo, o \param{advice} non è
+      un valore valido, o si è richiesto il rilascio (con
+      \const{MADV\_DONTNEED}) di pagine bloccate o condivise o si è usato
+      \const{MADV\_MERGEABLE} o \const{MADV\_UNMERGEABLE} ma il kernel non è
+      stato compilato per il relativo supporto.
+    \item[\errcode{EIO}] la paginazione richiesta eccederebbe i limiti (vedi
+      sez.~\ref{sec:sys_resource_limit}) sulle pagine residenti in memoria del
+      processo (solo in caso di \const{MADV\_WILLNEED}).
+    \item[\errcode{ENOMEM}] gli indirizzi specificati non sono mappati, o, in
+      caso \const{MADV\_WILLNEED}, non c'è sufficiente memoria per soddisfare
+      la richiesta.
+  \end{errlist}
+  ed inoltre \errval{EAGAIN} e \errval{ENOSYS} nel loro significato generico.}
+\end{funcproto}
+
+La sezione di memoria sulla quale si intendono fornire le indicazioni deve
+essere indicata con l'indirizzo iniziale \param{start} e l'estensione
+\param{length}, il valore di \param{start} deve essere allineato,
+mentre \param{length} deve essere un numero positivo; la versione di Linux
+consente anche un valore nullo per \param{length}, inoltre se una parte
+dell'intervallo non è mappato in memoria l'indicazione viene comunque
+applicata alle restanti parti, anche se la funzione ritorna un errore di
+\errval{ENOMEM}.
+
+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 \textit{read-ahead} (vedi sez.~\ref{sec:file_fadvise}) e del
+caching dei dati.
+
+\begin{table}[!htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10 cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{MADV\_DONTNEED}& non ci si aspetta nessun accesso nell'immediato
+                            futuro, pertanto le pagine possono essere
+                            liberate dal kernel non appena necessario; l'area
+                            di memoria resterà accessibile, ma un accesso
+                            richiederà che i dati vengano ricaricati dal file
+                            a cui la mappatura fa riferimento.\\
+    \const{MADV\_NORMAL}  & nessuna indicazione specifica, questo è il valore
+                            di default usato quando non si è chiamato
+                            \func{madvise}.\\
+    \const{MADV\_RANDOM}  & ci si aspetta un accesso casuale all'area
+                            indicata, pertanto l'applicazione di una lettura
+                            anticipata con il meccanismo del
+                            \textit{read-ahead} (vedi 
+                            sez.~\ref{sec:file_fadvise}) è di
+                            scarsa utilità e verrà disabilitata.\\
+    \const{MADV\_SEQUENTIAL}& ci si aspetta un accesso sequenziale al file,
+                            quindi da una parte sarà opportuno eseguire una
+                            lettura anticipata, e dall'altra si potranno
+                            scartare immediatamente le pagine una volta che
+                            queste siano state lette.\\
+    \const{MADV\_WILLNEED}& ci si aspetta un accesso nell'immediato futuro,
+                            pertanto l'applicazione del \textit{read-ahead}
+                            deve essere incentivata.\\
+    \hline
+    \const{MADV\_DONTDUMP}& esclude da un \textit{core dump} (vedi
+                            sez.~\ref{sec:sig_standard}) le pagine 
+                            specificate, viene usato per evitare di scrivere
+                            su disco dati relativi a zone di memoria che si sa
+                            non essere utili in un \textit{core dump}.\\
+    \const{MADV\_DODUMP}  & rimuove l'effetto della precedente
+                            \const{MADV\_DONTDUMP} (dal kernel 3.4).\\ 
+    \const{MADV\_DONTFORK}& impedisce che l'intervallo specificato venga
+                            ereditato dal processo figlio dopo una
+                            \func{fork}; questo consente di evitare che il
+                            meccanismo del \textit{copy on write} effettui la
+                            rilocazione delle pagine quando il padre scrive
+                            sull'area di memoria dopo la \func{fork}, cosa che
+                            può causare problemi per l'hardware che esegue
+                            operazioni in DMA su quelle pagine (dal kernel
+                            2.6.16).\\
+    \const{MADV\_DOFORK}  & rimuove l'effetto della precedente
+                            \const{MADV\_DONTFORK} (dal kernel 2.6.16).\\ 
+    \const{MADV\_HUGEPAGE}& abilita il meccanismo delle \textit{Transparent
+                              Huge Page} (vedi sez.~\ref{sec:huge_pages})
+                            sulla regione indicata; se questa è allineata
+                            alle relative dimensioni il kernel alloca
+                            direttamente delle \textit{huge page}; è
+                            utilizzabile solo con mappature anomime private
+                            (dal kernel 2.6.38).\\
+    \const{MADV\_NOHUGEPAGE}& impedisce che la regione indicata venga
+                            collassata in eventuali \textit{huge page} (dal
+                            kernel 2.6.38).\\
+    \const{MADV\_HWPOISON} &opzione ad uso di debug per verificare codice
+                            che debba gestire errori nella gestione della
+                            memoria; richiede una apposita opzione di
+                            compilazione del kernel, privilegi amministrativi
+                            (la capacità \const{CAP\_SYS\_ADMIN}) e provoca
+                            l'emissione di un segnale di \const{SIGBUS} dal
+                            programma chiamante e rimozione della mappatura
+                            (dal kernel 2.6.32).\\
+    \const{MADV\_SOFT\_OFFLINE}&opzione utilizzata per il debug del
+                            codice di verifica degli errori di gestione
+                            memoria, richiede una apposita opzione di
+                            compilazione (dal kernel 2.6.33).\\
+    \const{MADV\_MERGEABLE}& marca la pagina come accorpabile, indicazione
+                            principalmente ad uso dei sistemi di
+                            virtualizzazione\footnotemark (dal kernel 2.6.32).\\
+    \const{MADV\_REMOVE}  & libera un intervallo di pagine di memoria ed il
+                            relativo supporto sottostante; è supportato
+                            soltanto sui filesystem in RAM \textit{tmpfs} e
+                            \textit{shmfs} se usato su altri tipi di
+                            filesystem causa un errore di \errcode{ENOSYS}
+                            (dal kernel 2.6.16).\\
+    \const{MADV\_UNMERGEABLE}& rimuove l'effetto della precedente
+                            \const{MADV\_MERGEABLE} (dal kernel 2.6.32). \\
+     \hline
+  \end{tabular}
+  \caption{Valori dell'argomento \param{advice} di \func{madvise}.}
+  \label{tab:madvise_advice_values}
+\end{table}
+
+\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}}
+  e la documentazione nei sorgenti del kernel
+  (\texttt{Documentation/vm/ksm.txt}).} 
+
+
+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; questo comportamento differisce da quanto specificato nello
+standard.
+
+Nello standard POSIX.1-2001 è prevista una ulteriore funzione
+\funcd{posix\_madvise} che su Linux viene reimplementata utilizzando
+\func{madvise}; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{sys/mman.h}
+\fdecl{int posix\_madvise(void *start, size\_t lenght, int advice)}
+\fdesc{Fornisce indicazioni sull'uso previsto di un segmento di memoria.} 
+}
+
+{La funzione ritorna $0$ in caso di successo ed un valore positivo per un
+  errore, nel qual caso \var{errno} assumerà uno dei valori:
+  \begin{errlist}
+    \item[\errcode{EINVAL}] \param{start} non è allineato alla dimensione di
+      una pagina, \param{length} ha un valore negativo, o \param{advice} non è
+      un valore valido.
+    \item[\errcode{ENOMEM}] gli indirizzi specificati non sono nello spazio di
+      indirizzi del processo.
+  \end{errlist}
+}
+\end{funcproto}
+
+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
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{POSIX\_MADV\_DONTNEED}& analogo a \const{MADV\_DONTNEED}.\\
+    \const{POSIX\_MADV\_NORMAL}  & identico a \const{MADV\_NORMAL}.\\
+    \const{POSIX\_MADV\_RANDOM}  & identico a \const{MADV\_RANDOM}.\\
+    \const{POSIX\_MADV\_SEQUENTIAL}& identico a \const{MADV\_SEQUENTIAL}.\\
+    \const{POSIX\_MADV\_WILLNEED}& identico a \const{MADV\_WILLNEED}.\\
+     \hline
+  \end{tabular}
+  \caption{Valori dell'argomento \param{advice} di \func{posix\_madvise}.}
+  \label{tab:posix_madvise_advice_values}
+\end{table}
+
+
+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,
+che viene considerato distruttivo.
+
+
+
+\subsection{I/O vettorizzato: \func{readv} e \func{writev}}
+\label{sec:file_multiple_io}
+
+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 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{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
+    argomenti (ad esempio \param{count} è maggiore di \const{IOV\_MAX}).
+  \end{errlist}
+  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
+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 \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
+\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
+\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}
+
+
+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, 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
+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: 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
+                                 \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. 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; 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
+                                 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}
 
-\subsection{L'\textit{advisory locking}}
-\label{sec:file_record_locking}
 
-La prima modalità di file locking che è stata implementata nei sistemi
-unix-like è quella che viene usualmente chiamata \textit{advisory locking}, in
-quanto è il processo, e non il sistema, che si incarica di verificare se
-esiste una condizione di blocco per l'accesso ai file.
+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 \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=3.5cm]{img/splice_copy}
+  \caption{Struttura del flusso di dati usato dal programma \texttt{splicecp}.}
+  \label{fig:splicecp_data_flux}
+\end{figure}
 
+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}[!htb]
+  \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}
 
-\subsection{Il \textit{mandatory locking}}
-\label{sec:file_mand_locking}
+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
+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 in \textit{kernel
+  space}.
 
-Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4, 
+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 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 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 21-23}).
 
+Una volta completata con successo la lettura si avvia il ciclo di scrittura
+(\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
+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 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
+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 \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 \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{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}.} 
+}
+
+{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{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
+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 \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:
+
+\begin{funcproto}{
+\fhead{fcntl.h}
+\fdecl{long tee(int fd\_in, int fd\_out, size\_t len, unsigned int
+    flags)}
+\fdesc{Duplica i dati da una \textit{pipe} ad un'altra.} 
+}
+
+{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{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}
+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 \param{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 \textit{pipe} è
+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 \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}[!htb]
+  \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, 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 11-32}) inizia con la chiamata a
+\func{tee} che duplica il contenuto dello standard input sullo standard output
+(\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 14}), se
+è negativo c'è stato un errore, ed allora si ripete la chiamata se questo è
+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}:
+occorre sottolineare che benché finora si sia parlato di trasferimenti o copie
+di dati in realtà nella implementazione di queste \textit{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 \url{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} (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{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.} 
+}
+
+{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{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
+\param{count} byte, in modo da portarlo in cache.  La funzione usa la memoria
+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,
+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} (anche se
+l'argomento \param{len} è stato modificato da \type{size\_t} a \type{off\_t}
+nella revisione POSIX.1-2003 TC1) che consente di ``\textsl{avvisare}'' il
+kernel sulle modalità con cui si intende accedere nel futuro ad una certa
+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}.} è:
+
+
+\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{funcproto}
+
+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, ma
+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}
+
+Come \func{madvise} anche \func{posix\_fadvise} si appoggia al sistema della
+memoria virtuale ed al meccanismo standard del \textit{read-ahead} utilizzato
+dal kernel; in particolare utilizzando il valore
+\const{POSIX\_FADV\_SEQUENTIAL} si raddoppia la dimensione dell'ammontare di
+dati letti preventivamente rispetto al default, aspettandosi appunto una
+lettura sequenziale che li utilizzerà, mentre con \const{POSIX\_FADV\_RANDOM}
+si disabilita del tutto il suddetto meccanismo, dato che con un accesso del
+tutto casuale è inutile mettersi a leggere i dati immediatamente successivi
+gli attuali; infine l'uso di \const{POSIX\_FADV\_NORMAL} consente di
+riportarsi al comportamento di default.
+
+Le due modalità \const{POSIX\_FADV\_NOREUSE} e \const{POSIX\_FADV\_WILLNEED}
+fino al kernel 2.6.18 erano equivalenti, a partire da questo kernel la prima
+viene non ha più alcun effetto, mentre la seconda dà inizio ad una lettura in
+cache della regione del file indicata.  La quantità di dati che verranno letti
+è ovviamente limitata in base al carico che si viene a creare sul sistema
+della memoria virtuale, ma in genere una lettura di qualche megabyte viene
+sempre soddisfatta (ed un valore superiore è solo raramente di qualche
+utilità). In particolare l'uso di \const{POSIX\_FADV\_WILLNEED} si può
+considerare l'equivalente POSIX di \func{readahead}.
+
+Infine con \const{POSIX\_FADV\_DONTNEED} si dice al kernel di liberare le
+pagine di cache occupate dai dati presenti nella regione di file indicata.
+Questa è una indicazione utile che permette di alleggerire il carico sulla
+cache, ed un programma può utilizzare periodicamente questa funzione per
+liberare pagine di memoria da dati che non sono più utilizzati per far posto a
+nuovi dati utili; la pagina di manuale riporta l'esempio dello streaming di
+file di grosse dimensioni, dove le pagine occupate dai dati già inviati
+possono essere tranquillamente scartate.
+
+Sia \func{posix\_fadvise} che \func{readahead} attengono alla ottimizzazione
+dell'accesso in lettura; lo standard POSIX.1-2001 prevede anche una funzione
+specifica per le operazioni di scrittura, \funcd{posix\_fallocate} (la
+funzione è stata introdotta a partire dalle glibc 2.1.94), che consente di
+preallocare dello spazio disco per assicurarsi che una seguente scrittura non
+fallisca, il suo prototipo, anch'esso disponibile solo se si definisce la
+macro \macro{\_XOPEN\_SOURCE} ad almeno 600, è:
+
+\begin{funcproto}{
+\fhead{fcntl.h}
+\fdecl{int posix\_fallocate(int fd, off\_t offset, off\_t len)}
+\fdesc{Richiede la allocazione di spazio disco per un file.} 
+}
+
+{La funzione ritorna $0$ in caso di successo e direttamente un codice di
+  errore altrimenti, in tal caso \var{errno} non viene impostato, e si otterrà
+  direttamente uno dei valori:
+  \begin{errlist}
+    \item[\errcode{EBADF}] l'argomento \param{fd} non è un file descriptor
+      valido o non è aperto in scrittura.
+    \item[\errcode{EINVAL}] o \param{offset} o \param{len} sono minori di
+      zero.
+    \item[\errcode{EFBIG}] il valore di (\param{offset} + \param{len}) eccede
+      la dimensione massima consentita per un file.
+    \item[\errcode{ENODEV}] l'argomento \param{fd} non fa riferimento ad un
+      file regolare.
+    \item[\errcode{ENOSPC}] non c'è sufficiente spazio disco per eseguire
+      l'operazione. 
+    \item[\errcode{ESPIPE}] l'argomento \param{fd} è una \textit{pipe}.
+  \end{errlist}
+}
+\end{funcproto}
+
+La funzione assicura che venga allocato sufficiente spazio disco perché sia
+possibile scrivere sul file indicato dall'argomento \param{fd} nella regione
+che inizia dalla posizione \param{offset} e si estende per \param{len} byte;
+se questa regione si estende oltre la fine del file le dimensioni di
+quest'ultimo saranno incrementate di conseguenza. Dopo aver eseguito con
+successo la funzione è garantito che una successiva scrittura nella regione
+indicata non fallirà per mancanza di spazio disco. La funzione non ha nessun
+effetto né sul contenuto, né sulla posizione corrente del file.
+
+Ci si può chiedere a cosa possa servire una funzione come
+\func{posix\_fallocate} dato che è sempre possibile ottenere l'effetto voluto
+eseguendo esplicitamente sul file la scrittura di una serie di zeri (usando
+\funcd{pwrite} per evitare spostamenti della posizione corrente sul file) per
+l'estensione di spazio necessaria qualora il file debba essere esteso o abbia
+dei buchi.\footnote{si ricordi che occorre scrivere per avere l'allocazione e
+  che l'uso di \func{truncate} per estendere un file creerebbe soltanto uno
+  \textit{sparse file} (vedi sez.~\ref{sec:file_lseek}) senza una effettiva
+  allocazione dello spazio disco.}  In realtà questa è la modalità con cui la
+funzione veniva realizzata nella prima versione fornita dalle \acr{glibc}, per
+cui la funzione costituiva in sostanza soltanto una standardizzazione delle
+modalità di esecuzione di questo tipo di allocazioni.
+
+Questo metodo, anche se funzionante, comporta però l'effettiva esecuzione una
+scrittura su tutto lo spazio disco necessario, da fare al momento della
+richiesta di allocazione, pagandone il conseguente prezzo in termini di
+prestazioni; il tutto quando in realtà servirebbe solo poter riservare lo
+spazio per poi andarci a scrivere, una sola volta, quando il contenuto finale
+diventa effettivamente disponibile.  Per poter fare tutto questo è però
+necessario il supporto da parte del kernel, e questo è divenuto disponibile
+solo a partire dal kernel 2.6.23 in cui è stata introdotta la nuova
+\textit{system call} \func{fallocate},\footnote{non è detto che la funzione
+  sia disponibile per tutti i filesystem, ad esempio per XFS il supporto è
+  stato introdotto solo a partire dal kernel 2.6.25.}  che consente di
+realizzare direttamente all'interno del kernel l'allocazione dello spazio
+disco così da poter realizzare una versione di \func{posix\_fallocate} con
+prestazioni molto più elevate; nelle \acr{glibc} la nuova \textit{system call}
+viene sfruttata per la realizzazione di \func{posix\_fallocate} a partire
+dalla versione 2.10.
+
+Trattandosi di una funzione di servizio, ed ovviamente disponibile
+esclusivamente su Linux, inizialmente \funcd{fallocate} non era stata definita
+come funzione di libreria,\footnote{pertanto poteva essere invocata soltanto
+  in maniera indiretta con l'ausilio di \func{syscall}, vedi
+  sez.~\ref{sec:proc_syscall}, come \code{long fallocate(int fd, int mode,
+      loff\_t offset, loff\_t len)}.} ma a partire dalle \acr{glibc} 2.10 è
+  stato fornito un supporto esplicito; il suo prototipo è:
+
+\begin{funcproto}{
+\fhead{fcntl.h} 
+\fdecl{int fallocate(int fd, int mode, off\_t offset, off\_t len)}
+\fdesc{Prealloca dello spazio disco per 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}] \param{fd} non fa riferimento ad un file descriptor
+      valido aperto in scrittura.
+    \item[\errcode{EFBIG}] la somma di \param{offset} e \param{len} eccede le
+      dimensioni massime di un file. 
+    \item[\errcode{EINVAL}] \param{offset} è minore di zero o \param{len} è
+      minore o uguale a zero. 
+    \item[\errcode{ENODEV}] \param{fd} non fa riferimento ad un file ordinario
+      o a una directory. 
+    \item[\errcode{EPERM}] il file è immutabile o \textit{append-only} (vedi
+      sez.~\ref{sec:file_perm_overview}).
+    \item[\errcode{ENOSYS}] il filesystem contenente il file associato
+      a \param{fd} non supporta \func{fallocate}.
+    \item[\errcode{EOPNOTSUPP}] il filesystem contenente il file associato
+      a \param{fd} non supporta l'operazione \param{mode}.
+  \end{errlist}
+  ed inoltre \errval{EINTR}, \errval{EIO} e \errval{ENOSPC} nel loro significato
+  generico.}
+\end{funcproto}
+
+La funzione prende gli stessi argomenti di \func{posix\_fallocate} con lo
+stesso significato, a cui si aggiunge l'argomento \param{mode} che indica le
+modalità di allocazione; se questo è nullo il comportamento è identico a
+quello di \func{posix\_fallocate} e si può considerare \func{fallocate} come
+l'implementazione ottimale della stessa a livello di kernel.
+
+Inizialmente l'unico altro valore possibile per \param{mode} era
+\const{FALLOC\_FL\_KEEP\_SIZE} che richiede che la dimensione del file (quella
+ottenuta nel campo \var{st\_size} di una struttura \struct{stat} dopo una
+chiamata a \texttt{fstat}) non venga modificata anche quando la somma
+di \param{offset} e \param{len} eccede la dimensione corrente, che serve
+quando si deve comunque preallocare dello spazio per scritture in append. In
+seguito sono stati introdotti altri valori, riassunti in
+tab.\ref{tab:fallocate_mode}, per compiere altre operazioni relative alla
+allocazione dello spazio disco dei file.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|p{10cm}|}
+    \hline
+    \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{FALLOC\_FL\_INSERT}     & .\\
+    \const{FALLOC\_FL\_COLLAPSE\_RANGE}& .\\ 
+    \const{FALLOC\_FL\_KEEP\_SIZE} & Mantiene invariata la dimensione del
+                                     file, pur allocando lo spazio disco anche
+                                     oltre la dimensione corrente del file.\\
+    \const{FALLOC\_FL\_PUNCH\_HOLE}& Crea un \textsl{buco} nel file (vedi
+                                     sez.~\ref{sec:file_lseek}) rendendolo una
+                                     \textit{sparse file} (dal kernel
+                                     2.6.38).\\  
+    \const{FALLOC\_FL\_ZERO\_RANGE}& .\\ 
+    \hline
+  \end{tabular}
+  \caption{Valori delle costanti usabili per l'argomento \param{mode} di
+    \func{fallocate}.}
+  \label{tab:fallocate_mode}
+\end{table}
+
+In particolare con \const{FALLOC\_FL\_PUNCH\_HOLE} è possibile scartare il
+contenuto della sezione di file indicata da \param{offser} e \param{len},
+creando un \textsl{buco} (si ricordi quanto detto in
+sez.~\ref{sec:file_lseek}); i blocchi del file interamente contenuti
+nell'intervallo verranno disallocati, la parte di intervallo contenuta
+parzialmente in altri blocchi verrà riempita con zeri e la lettura dal file
+restituirà degli zeri per tutto l'intervallo indicato. In sostanza si rende il
+file uno \textit{sparse file} a posteriori.
+
+% vedi http://lwn.net/Articles/226710/ e http://lwn.net/Articles/240571/
+% http://kernelnewbies.org/Linux_2_6_23
+
+% TODO aggiungere FALLOC_FL_ZERO_RANGE e FALLOC_FL_COLLAPSE_RANGE, inseriti
+% nel kernel 3.15 (sul secondo vedi http://lwn.net/Articles/589260/), vedi
+% anche http://lwn.net/Articles/629965/
+
+% TODO aggiungere FALLOC_FL_INSERT vedi  http://lwn.net/Articles/629965/
+
+
+% TODO non so dove trattarli, ma dal 2.6.39 ci sono i file handle, vedi
+% http://lwn.net/Articles/432757/ 
+
+
+% LocalWords:  dell'I locking multiplexing cap sez system call socket BSD GID
+% LocalWords:  descriptor client deadlock NONBLOCK EAGAIN polling select kernel
+% LocalWords:  pselect like sys unistd int fd readfds writefds exceptfds struct
+% LocalWords:  timeval errno EBADF EINTR EINVAL ENOMEM sleep tab signal void of
+% LocalWords:  CLR ISSET SETSIZE POSIX read NULL nell'header l'header glibc fig
+% LocalWords:  libc header psignal sigmask SOURCE XOPEN timespec sigset race DN
+% LocalWords:  condition sigprocmask tut self trick oldmask poll XPG pollfd l'I
+% LocalWords:  ufds unsigned nfds RLIMIT NOFILE EFAULT ndfs events revents hung
+% LocalWords:  POLLIN POLLRDNORM POLLRDBAND POLLPRI POLLOUT POLLWRNORM POLLERR
+% LocalWords:  POLLWRBAND POLLHUP POLLNVAL POLLMSG SysV stream ASYNC SETOWN FAQ
+% LocalWords:  GETOWN fcntl SETFL SIGIO SETSIG Stevens driven siginfo sigaction
+% LocalWords:  all'I nell'I Frequently Unanswered Question SIGHUP lease holder
+% LocalWords:  breaker truncate write SETLEASE arg RDLCK WRLCK UNLCK GETLEASE
+% LocalWords:  uid capabilities capability EWOULDBLOCK notify dall'OR ACCESS st
+% LocalWords:  pread readv MODIFY pwrite writev ftruncate creat mknod mkdir buf
+% LocalWords:  symlink rename DELETE unlink rmdir ATTRIB chown chmod utime lio
+% LocalWords:  MULTISHOT thread linkando librt layer aiocb asyncronous control
+% LocalWords:  block ASYNCHRONOUS lseek fildes nbytes reqprio PRIORITIZED sigev
+% LocalWords:  PRIORITY SCHEDULING opcode listio sigevent signo value function
+% LocalWords:  aiocbp ENOSYS append error const EINPROGRESS fsync return ssize
+% LocalWords:  DSYNC fdatasync SYNC cancel ECANCELED ALLDONE CANCELED suspend
+% LocalWords:  NOTCANCELED list nent timout sig NOP WAIT NOWAIT size count iov
+% LocalWords:  iovec vector EOPNOTSUPP EISDIR len memory mapping mapped swap NB
+% LocalWords:  mmap length prot flags off MAP FAILED ANONYMOUS EACCES SHARED SH
+% LocalWords:  only ETXTBSY DENYWRITE ENODEV filesystem EPERM EXEC noexec table
+% LocalWords:  ENFILE lenght segment violation SIGSEGV FIXED msync munmap copy
+% LocalWords:  DoS Denial Service EXECUTABLE NORESERVE LOCKED swapping stack fs
+% LocalWords:  GROWSDOWN ANON POPULATE prefaulting SIGBUS fifo VME fork old SFD
+% LocalWords:  exec atime ctime mtime mprotect addr mremap address new Failed
+% LocalWords:  long MAYMOVE realloc VMA virtual Ingo Molnar remap pages pgoff
+% LocalWords:  dall' fault cache linker prelink advisory discrectionary lock fl
+% LocalWords:  flock shared exclusive operation dup inode linked NFS cmd ENOLCK
+% LocalWords:  EDEADLK whence SEEK CUR type pid GETLK SETLK SETLKW HP EACCESS
+% LocalWords:  switch bsd lockf mandatory SVr sgid group root mount mand TRUNC
+% LocalWords:  SVID UX Documentation sendfile dnotify inotify NdA ppoll fds add
+% LocalWords:  init EMFILE FIONREAD ioctl watch char pathname uint mask ENOSPC
+% LocalWords:  CLOSE NOWRITE MOVE MOVED FROM TO rm wd event page ctl acquired
+% LocalWords:  attribute Universe epoll Solaris kqueue level triggered Jonathan
+% LocalWords:  Lemon BSDCON edge Libenzi kevent backporting epfd EEXIST ENOENT
+% LocalWords:  MOD wait EPOLLIN EPOLLOUT EPOLLRDHUP SOCK EPOLLPRI EPOLLERR one
+% LocalWords:  EPOLLHUP EPOLLET EPOLLONESHOT shot maxevents ctlv ALL DONT HPUX
+% LocalWords:  FOLLOW ONESHOT ONLYDIR FreeBSD EIO caching sysctl instances name
+% LocalWords:  watches IGNORED ISDIR OVERFLOW overflow UNMOUNT queued cookie ls
+% LocalWords:  NUL sizeof casting printevent nread limits sysconf SC wrapper Di
+% LocalWords:  splice result argument DMA controller zerocopy Linus Larry Voy
+% LocalWords:  Jens Anxboe vmsplice seek ESPIPE GIFT TCP CORK MSG splicecp nr
+% LocalWords:  nwrite segs patch readahead posix fadvise TC advice FADV NORMAL
+% LocalWords:  SEQUENTIAL NOREUSE WILLNEED DONTNEED streaming fallocate EFBIG
+% LocalWords:  POLLRDHUP half close pwait Gb madvise MADV ahead REMOVE tmpfs it
+% LocalWords:  DONTFORK DOFORK shmfs preadv pwritev syscall linux loff head XFS
+% LocalWords:  MERGEABLE EOVERFLOW prealloca hole FALLOC KEEP stat fstat union
+% LocalWords:  conditions sigwait CLOEXEC signalfd sizemask SIGKILL SIGSTOP ssi
+% LocalWords:  sigwaitinfo FifoReporter Windows ptr sigqueue named timerfd TFD
+% 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 TLOCK ULOCK EPOLLWAKEUP
 
 
 %%% Local Variables: 
 %%% mode: latex
 %%% TeX-master: "gapil"
 %%% End: 
+