Ancora su AIO.
[gapil.git] / fileadv.tex
index 6737554729c23493928bed51931c1a4a9c911af8..f95fa683adba2870995e9c0cb301f63bd055e30f 100644 (file)
-\chapter{I/O avanzato}
+\chapter{La gestione avanzata dei file}
 \label{cha:file_advanced}
 
-In questo capitolo affronteremo le tematiche della gestione avanzata delle
-funzioni di input/ouput, prenderemo in esame il \textit{file locking}, la
-gestione dell'input/output da più file, per concludere con la gestione dei
-file mappati in memoria.
+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}.
 
 
-\section{L'I/O avanzato}
+\section{Le funzioni di I/O avanzato}
 \label{sec:file_advanced_io}
 
-Uno dei problemi che ci si trova ad affrontare con le funzioni ordinarie
-trattate in \capref{cha:file_unix_interface} è quello in cui si devono
-eseguire su più di un file descriptor delle operazioni che possono bloccarsi:
-il problema è che mentre si è bloccati su un file su di un'altro potrebbero
-essere presenti dati da leggere.
-
-In questa sezione vedremo come si possono affrontare queste problematiche,
-quali sono le soluzioni possibili e quali i meccanismi il kernel e le librerie
-ci mettono a disposizione.
+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}
 
-Una prima soluzione per evitare di bloccarsi nelle operazioni di I/O è quella
-di utilizzare la modalità \textsl{non-bloccante}. 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.} 
-In particolare le operazioni di lettura possono bloccarsi quando non ci sono
-dati disponibili sul descrittore su cui si sta operando.
+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 essi 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 è possibile prevenire
-questo tipo di comportamento aprendo il file in modalità non bloccante,
-specificando il flag \macro{O\_NONBLOCK}. In questo caso le funzioni che si
-sarebbero bloccate ritornano immediatamente restituendo l'errore
-\macro{EAGAIN}.
-
-L'utilizzo di questa modalità di I/O permette allora di risolvere il problema 
-
-
-%\section{I/O asincrono}
-%\label{sec:file_asynchronous}
-
-%Non supportato in Linux, in BSD e SRv4 c'è, ma usando il segnale \macro{SIGIO}
-%per indicare che i dati sono disponibili, può essere usato in maniera semplice
-%con un solo file per processo (altrimenti non sarebbe più possibile
-%distinguere da quale file proviene l'attività che ha causato l'emissione del
-%segnale).
+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}.
 
-\subsection{L'I/O asincrono}
-\label{sec:file_asyncronous_io}
+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}}
+\subsection{L'I/O multiplexing}
 \label{sec:file_multiplexing}
 
+Per superare il problema di dover usare il \textit{polling} per controllare la
+possibilità di effettuare operazioni su 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 in attesa che l'accesso diventi
+possibile.  Il primo ad introdurre questa modalità di operazione, chiamata
+usualmente \textit{I/O multiplexing}, è stato BSD,\footnote{la funzione è
+  apparsa in BSD4.2 e standardizzata in BSD4.4, ma è stata portata su tutti i
+  sistemi che supportano i \textit{socket}, compreso le varianti di System V.}
+con la funzione \func{select}, il cui prototipo è:
+\begin{functions}
+  \headdecl{sys/time.h}
+  \headdecl{sys/types.h}
+  \headdecl{unistd.h}
+  \funcdecl{int select(int n, fd\_set *readfds, fd\_set *writefds, fd\_set
+    *exceptfds, struct timeval *timeout)}
+  
+  Attende che uno dei file descriptor degli insiemi specificati diventi
+  attivo.
+  
+  \bodydesc{La funzione in caso di successo restituisce il numero di file
+    descriptor (anche nullo) che sono attivi, 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{functions}
+
+La funzione mette il processo in stato di \textit{sleep} (vedi
+\tabref{tab:proc_proc_states}) fintanto che almeno uno dei file descriptor
+degli insiemi specificati (\param{readfds}, \param{writefds} e
+\param{exceptfds}), non diventa attivo, per un tempo massimo specificato da
+\param{timeout}.
+
+Per specificare quali file descriptor si intende \textsl{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/time.h}
+  \headdecl{sys/types.h}
+  \headdecl{unistd.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}
+
+In genere un \textit{file descriptor set} può contenere fino ad un massimo di
+\macro{FD\_SETSIZE} file descriptor.  Questo valore in origine corrispondeva
+al limite per il 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, non c'è più un limite
+massimo, esso indica le dimensioni massime dei numeri usati nei \textit{file
+  descriptor set}.
+
+La funzione richiede di specificare tre insiemi distinti di file descriptor;
+il primo, \param{readfds}, verrà osservato per rilevare la disponibilità di
+effettuare una lettura, il secondo, \param{writefds}, per verificare la
+possibilità effettuare una scrittura ed il terzo, \param{exceptfds}, per
+verificare l'esistenza di condizioni eccezionali (come i messaggi urgenti su
+un \textit{socket}\index{socket}, vedi \secref{sec:xxx_urgent}).
+
+La funzione inoltre richiede anche di specificare, tramite l'argomento
+\param{n}, un valore massimo del numero dei file descriptor usati
+nell'insieme; si può usare il già citato \macro{FD\_SETSIZE}, oppure il numero
+più alto dei file descriptor usati nei tre insiemi, aumentato di uno.
+
+Infine l'argomento \param{timeout}, specifica un tempo massimo di
+attesa\footnote{il tempo è valutato come \textit{elapsed time}.} prima che la
+funzione ritorni; se settato a \macro{NULL} la funzione attende
+indefinitamente. Si può specificare anche un tempo nullo (cioè una \var{struct
+  timeval} con i campi settati a zero), qualora si voglia semplicemente
+controllare lo stato corrente dei file descriptor.
+
+La funzione restituisce il totale dei file descriptor pronti nei tre insiemi,
+il valore zero indica sempre che si è raggiunto un timeout. Ciascuno dei tre
+insiemi viene sovrascritto per indicare quale file descriptor è pronto per le
+operazioni ad esso relative, in modo da poterlo controllare con la macro
+\macro{FD\_ISSET}. In caso di errore la funzione restituisce -1 e gli insiemi
+non vengono toccati.
+
+In Linux \func{select} modifica anche il valore di \param{timeout}, settandolo
+al tempo restante; questo è utile quando la funzione viene interrotta da un
+segnale, in tal caso infatti si ha un errore di \macro{EINTR}, ed occorre
+rilanciare la funzione; in questo modo non è necessario ricalcolare tutte le
+volte il tempo rimanente.\footnote{questo può causare problemi di portabilità
+  sia quando si trasporta codice scritto su Linux che legge questo valore, sia
+  quando si usano programmi scritti per altri sistemi che non dispongono di
+  questa caratteristica e ricalcolano \param{timeout} tutte le volte. In
+  genere la caratteristica è disponibile nei sistemi che derivano da System V
+  e non disponibile per quelli che derivano da BSD.}
+
+Come accennato l'interfaccia di \func{select} è una estensione di BSD; anche
+System V ha introdotto una sua interfaccia per gestire l'\textit{I/O
+  multiplexing}, basata sulla funzione \func{poll},\footnote{la funzione è
+  prevista dallo standard XPG4, ed è stata introdotta in Linux come system
+  call a partire dal kernel 2.1.23 e dalle \acr{libc} 5.4.28.} il cui prototipo è:
+\begin{prototype}{sys/poll.h}
+  {int poll(struct pollfd *ufds, unsigned int nfds, int timeout)}
+
+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:
+  \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.
+  \end{errlist}
+  ed inoltre \macro{EFAULT} e \macro{ENOMEM}.}
+\end{prototype}
+
+La funzione tiene sotto controllo un numero \param{ndfs} di file descriptor
+specificati attraverso un vettore di puntatori a strutture di tipo
+\type{pollfd}, la cui definizione è riportata in \figref{fig:file_pollfd}.
+Come \func{select} anche \func{poll} permette di interrompere l'attesa dopo un
+certo tempo, che va specificato attraverso \param{timeout} in numero di
+millisecondi (un valore negativo indica un'attesa indefinita).
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct pollfd {
+        int fd;           /* file descriptor */
+        short events;     /* requested events */
+        short revents;    /* returned events */
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \type{pollfd}, utilizzata per specificare le modalità
+    di controllo di un file descriptor alla funzione \func{poll}.}
+  \label{fig:file_pollfd}
+\end{figure}
+
+Per ciascun file da controllare deve essere opportunamente predisposta una
+struttura \type{pollfd}; nel campo \var{fd} deve essere specificato il file
+descriptor, mentre nel campo \var{events} il tipo di evento su cui si vuole
+attendere; quest'ultimo deve essere specificato come maschera binaria dei
+primi tre valori riportati in \tabref{tab:file_pollfd_flags} (gli altri
+vengono utilizzati solo per \var{revents} come valori in uscita).
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|c|l|}
+    \hline
+    \textbf{Flag} & \textbf{Valore} & \textbf{Significato} \\
+    \hline
+    \hline
+    \macro{POLLIN}    & 0x001 & È possibile la lettura immediata.\\
+    \macro{POLLPRI}   & 0x002 & Sono presenti dati urgenti.\\
+    \macro{POLLOUT}   & 0x004 & È possibile la scrittura immediata.\\
+    \hline
+    \macro{POLLERR}   & 0x008 & C'è una condizione di errore.\\
+    \macro{POLLHUP}   & 0x010 & Si è verificato un hung-up.\\
+    \macro{POLLNVAL}  & 0x020 & Il file descriptor non è aperto.\\
+    \hline
+    \macro{POLLRDNORM}& 0x040 & Sono disponibili in lettura dati normali.\\ 
+    \macro{POLLRDBAND}& 0x080 & Sono disponibili in lettura dati ad alta 
+                                priorità. \\
+    \macro{POLLWRNORM}& 0x100 & È possibile la scrittura di dati normali.  \\ 
+    \macro{POLLWRBAND}& 0x200 & È possibile la scrittura di dati ad 
+                                alta priorità. \\
+    \macro{POLLMSG}   & 0x400 & Estensione propria di Linux.\\
+    \hline    
+  \end{tabular}
+  \caption{Costanti per l'identificazione dei vari bit dei campi
+    \var{events} e \var{revents} di \type{pollfd}.}
+  \label{tab:file_pollfd_flags}
+\end{table}
+
+La funzione ritorna, restituendo il numero di file per i quali si è verificata
+una delle condizioni di attesa richieste o un errore. Lo stato dei file
+all'uscita della funzione viene restituito nel campo \var{revents} della
+relativa struttura \type{pollfd}, che viene settato alla maschera binaria dei
+valori riportati in \tabref{tab:file_pollfd_flags}, ed oltre alle tre
+condizioni specificate tramite \var{events} può riportare anche l'occorrere di
+una condizione di errore.
+
+Lo standard POSIX è rimasto a lungo senza primitive per l'\textit{I/O
+  multiplexing}, che è stata introdotto con le ultime revisioni dello standard
+(POSIX 1003.1g-2000 e POSIX 1003.1-2001). Esso prevede che tutte le funzioni
+ad esso relative vengano dichiarate nell'header \file{sys/select.h}, che
+sostituisce i precedenti, ed aggiunge a \func{select} una nuova funzione
+\func{pselect},\footnote{il supporto per lo standard POSIX 1003.1-2001, ed
+  l'header \file{sys/select.h}, compaiono in Linux a partire dalle \acr{glibc}
+  2.1. Le \acr{libc4} e \acr{libc5} non contengono questo header, le
+  \acr{glibc} 2.0 contengono una definizione sbagliata di \func{psignal},
+  senza l'argomento \param{sigmask}, la definizione corretta è presente dalle
+  \acr{glibc} 2.1-2.2.1 se si è definito \macro{\_GNU\_SOURCE} e nelle
+  \acr{glibc} 2.2.2-2.2.4 se si è definito \macro{\_XOPEN\_SOURCE} con valore
+  maggiore di 600.} il cui prototipo è:
+\begin{prototype}{sys/select.h}
+  {int pselect(int n, fd\_set *readfds, fd\_set *writefds, fd\_set *exceptfds,
+    struct timespec *timeout, sigset\_t *sigmask)}
+  
+  Attende che uno dei file descriptor degli insiemi specificati diventi
+  attivo.
+  
+  \bodydesc{La funzione in caso di successo restituisce il numero di file
+    descriptor (anche nullo) che sono attivi, 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 è sostanzialmente identica a \func{select}, solo che usa una
+struttura \type{timespec} per indicare con maggiore precisione il timeout e
+non ne aggiorna il valore in caso di interruzione, inoltre prende un argomento
+aggiuntivo \param{sigmask} che è il puntatore ad una maschera di segnali (si
+veda \secref{sec:sig_sigmask}). La maschera corrente viene sostituita da
+questa immediatamente prima di eseguire l'attesa, e ripristinata al ritorno
+della funzione.
+
+L'uso di \param{sigmask} è stato introdotto allo scopo di prevenire possibili
+race condition\footnote{in Linux però, non esistendo una system call apposita,
+  la funzione è implementata nelle \acr{glibc} usando \func{select}, e la
+  possibilità di una race condition resta.} quando si deve eseguire un test su
+una variabile settata da un manipolatore sulla base dell'occorrenza di un
+segnale per decidere se lanciare \func{select}. Fra il test e l'esecuzione è
+presente una finestra in cui potrebbe arrivare il segnale che non sarebbe
+rilevato; la race condition diventa superabile disabilitando il segnale prima
+del test e riabilitandolo poi grazie all'uso di \param{sigmask}.
+
+
+
+\subsection{L'\textsl{I/O asincrono}}
+\label{sec:file_asyncronous_io}
 
+Una modalità alternativa all'uso dell'\textit{I/O multiplexing} è quella di
+fare ricorso al cosiddetto \textsl{I/O asincrono}. 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.
+
+Abbiamo accennato in \secref{sec:file_open} che è possibile, attraverso l'uso
+del flag \macro{O\_ASYNC},\footnote{l'uso del flag di \macro{O\_ASYNC} e dei
+  comandi \macro{F\_SETOWN} e \macro{F\_GETOWN} per \func{fcntl} è specifico
+  di Linux e BSD.} aprire un file in modalità asincrona, così come è possibile
+attivare in un secondo tempo questa modalità settando questo flag attraverso
+l'uso di \func{fcntl} con il comando \macro{F\_SETFL} (vedi
+\secref{sec:file_fcntl}). 
+
+In realtà in questo caso non si tratta di I/O asincrono vero e proprio, quanto
+di un meccanismo asincrono di notifica delle variazione dello stato del file
+descriptor; quello che succede è che il sistema genera un segnale (normalmente
+\macro{SIGIO}, ma è possibile usarne altri) tutte le volte che diventa
+possibile leggere o scrivere dal file descriptor che si è posto in questa
+modalità. Si può inoltre selezionare, con il comando \macro{F\_SETOWN} di
+\func{fcntl}, quale processo (o gruppo di processi) riceverà il segnale. 
+
+In questo modo si può evitare l'uso delle funzioni \func{poll} o \func{select}
+che, quando vengono usate con un numero molto grande di file descriptor, non
+hanno buone prestazioni. In tal caso infatti la maggior parte del loro tempo
+di esecuzione è impegnato ad eseguire una scansione su tutti i file descriptor
+tenuti sotto controllo per determinare quali di essi (in genere una piccola
+percentuale) sono diventati attivi.
+
+Tuttavia con l'implementazione classica dei segnali questa modalità di I/O
+presenta notevoli problemi, dato che non è possibile determinare, quando sono
+più di uno, qual'è il file descriptor responsabile dell'emissione del segnale.
+Linux però supporta le estensioni POSIX.1b dei segnali che permettono di
+superare il problema facendo ricorso alle informazioni aggiuntive restituite
+attraverso la struttura \type{siginfo\_t}, utilizzando la forma estesa
+\var{sa\_sigaction} del manipolatore (si riveda quanto illustrato in
+\secref{sec:sig_sigaction}).
+
+Per far questo però occorre utilizzare le funzionalità dei segnali real-time
+(vedi \secref{sec:sig_real_time}) settando esplicitamente con il comando
+\macro{F\_SETSIG} di \func{fcntl} un segnale real-time da inviare in caso di
+I/O asincrono (il segnale di default è \macro{SIGIO}). In questo caso il
+manipolatore tutte le volte che riceverà \macro{SI\_SIGIO} come valore del
+campo \var{si\_code}\footnote{il valore resta \macro{SI\_SIGIO} qualunque sia
+  il segnale che si è associato all'I/O asincrono, ed indica appunto che il
+  segnale è stato generato a causa di attività nell'I/O asincrono.} di
+\type{siginfo\_t}, troverà nel campo \var{si\_fd} il valore del file
+descriptor che ha generato il segnale.
+
+Un secondo vantaggio dell'uso dei segnali real-time è che essendo dotati di
+una coda di consegna ogni segnale sarà associato ad uno solo file descriptor;
+inoltre sarà possibile stabilire delle priorità nella risposta a seconda del
+segnale usato. In questo modo si può identificare immediatamente un file su
+cui l'accesso è diventato possibile evitando completamente l'uso di funzioni
+come \func{poll} e \func{select}, almeno fintanto che non si satura la coda;
+si eccedono le dimensioni di quest'ultima; in tal caso infatti il kernel, non
+potendo più assicurare il comportamento corretto per un segnale real-time,
+invierà al suo posto un \var{SIGIO}, su cui si accumuleranno tutti i segnali
+in eccesso, e si dovrà determinare al solito modo quali sono i file diventati
+attivi.
+
+
+
+Benché la modalità di apertura asincrona di un file 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 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 anche una interfaccia apposita per l'I/O asincrono, che prevede un
+insieme di funzioni dedicate, completamente separate rispetto a quelle usate
+normalmente.
+
+In generale questa interfaccia è completamente astratta e può essere
+implementata sia direttamente nel kernel, che in user space attraverso l'uso
+di thread. Al momento\footnote{fino ai kernel della serie 2.4.x, nella serie
+  2.5.x è però iniziato un lavoro completo di riscrittura di tutto il sistema
+  di I/O, che prevede anche l'introduzione di un nuovo layer per l'I/O
+  asincrono.} esiste una sola versione stabile di questa interfaccia, quella
+delle \acr{glibc}, che è realizzata completamente in user space.  Esistono
+comunque vari progetti sperimentali (come il KAIO della SGI, o i patch di
+Benjamin La Haise) che prevedono un supporto diretto da parte del kernel.
+
+Lo standard prevede che tutte le operazioni di I/O asincrono siano controllate
+attraverso l'uso di una apposita struttura \type{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
+\file{aio.h}, è riportata in \figref{fig:file_aiocb}. Nello steso file è
+definita la macro \macro{\_POSIX\_ASYNCHRONOUS\_IO}, che dichiara la
+disponibilità di questa funzionalità.
+
+\begin{figure}[!htb]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \begin{lstlisting}[labelstep=0]{}%,frame=,indent=1cm]{}
+struct aiocb
+{
+    int aio_fildes;               /* File descriptor.  */
+    off_t aio_offset;             /* File offset */
+    int aio_lio_opcode;           /* Operation to be performed.  */
+    int aio_reqprio;              /* Request priority offset.  */
+    volatile void *aio_buf;       /* Location of buffer.  */
+    size_t aio_nbytes;            /* Length of transfer.  */
+    struct sigevent aio_sigevent; /* Signal number and value.  */
+};
+    \end{lstlisting}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \type{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 cui file descriptor deve essere specificato tramite il campo
+\var{aio\_fildes}; il file deve inolte supportare la funzione \func{lseek},
+pertanto terminali e pipe sono esclusi. Non c'è limite al numero di operazioni
+contemporanee effettuabili su un singolo file.
+
+Dato che più operazioni possono essere eseguita in maniera asincrona, il
+concetto di posizione corrente sul file viene a mancare; pertanto ciascuna
+operazione 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} poi
+andrà specificato l'indirizzo del buffer usato per l'I/O, ed in
+\var{aio\_nbytes} la lunghezza del trasferimento.
+
+Il campo \var{aio\_reqprio} permette invece di settare la priorità delle
+operazioni di I/O.\footnote{in generale perché ciò sia possibile occorre che
+  la piattaforma supporti questa caratteristica, questo viene indicato
+  definendo le macro \macro{\_POSIX\_PRIORITIZED\_IO}, e
+  \macro{\_POSIX\_PRIORITY\_SCHEDULING}.} La priorità viene settata a partire
+da quella del processo chiamante (vedi \secref{sec:proc_priority}), cui viene
+sottratto il valore di questo campo.
+
+
+
+Le due funzioni principali dell'interfaccia sono quelle per la lettura e
+scrittura, \func{aio\_read} e \func{aio\_write}, i cui prototipi sono:
+\begin{functions}
+  \headdecl{aio.h}
+  \funcdecl{int aio\_read(struct aiocb *aiocbp)}
+  Richiede una lettura asincrona sul file specificato tramite \param{aiocbp}.
+
+  \funcdecl{int aio\_write(struct aiocb *aiocbp)}
+  Richiede una scrittura asincrona sul file specificato tramite \param{aiocbp}.
+\end{functions}
+
+
+
+\subsection{I/O multiplo}
+\label{sec:file_multiple_io}
+
+Un caso abbastanza comune è quello in cui ci si trova a dover affrontare una
+serie multipla di operazioni di I/O, come una serie di letture o scritture di
+vari buffer. In questo caso
+
+
+
+\subsection{File mappati in memoria}
+\label{sec:file_memory_map}
 
+Una modalità alternativa di I/O, che usa una interfaccia completamente diversa
+rispetto a quella classica, è quella dei file \textsl{mappati in memoria}. In
+sostanza quello che si fa è usare il meccanismo della
+\textsl{paginazione}\index{paginazione} usato per la memoria virtuale (vedi
+\secref{sec:proc_mem_gen}) per trasformare vedere il file in una sezione dello
+spazio di indirizzi del processo, in modo che l'accesso a quest'ultimo con le
+normali operazioni di lettura e scrittura delle variabili in memoria, si
+trasformi in I/O sul file stesso.
 
 
 
-\section{File locking}
+\section{Il file locking}
 \label{sec:file_locking}
 
-In \secref{sec:file_sharing} abbiamo preso in esame le mosalità in cui un
-sistema unix-like gestisce la condivisione dei file. 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.
+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.
 
-Questo causa la possibilità di 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 imprevedebile il loro output sul file.
+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
+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
+bloccare l'accesso al file da parte di altri processi, così da evitare le
 sovrapposizioni, e garantire la atomicità delle operazioni di scrittura.
 
 
-\subsection{Il \textit{advisory locking}}
+\subsection{L'\textit{advisory locking}}
 \label{sec:file_record_locking}
 
 La prima modalità di file locking che è stata implementata nei sistemi
@@ -100,14 +519,11 @@ esiste una condizione di blocco per l'accesso ai file.
 \subsection{Il \textit{mandatory locking}}
 \label{sec:file_mand_locking}
 
-Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVR4, 
+Il \textit{mandatory locking} è una opzione introdotta inizialmente in SVr4, 
 
 
 
 
-\section{File mappati in memoria}
-\label{sec:file_memory_map}
-
 
 
 %%% Local Variables: