-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{prototype}{aio.h}
-{int aio\_suspend(const struct aiocb * const list[], int nent, const struct
- timespec *timeout)}
-
- Attende, per un massimo di \param{timeout}, il completamento di una delle
- operazioni specificate da \param{list}.
-
- \bodydesc{La funzione restituisce 0 se una (o più) operazioni sono state
- completate, e -1 in caso di errore nel qual caso \var{errno} assumerà uno
- dei valori:
- \begin{errlist}
- \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
- \param{timeout}.
- \item[\errcode{ENOSYS}] la funzione non è implementata.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
- \end{errlist}
- }
-\end{prototype}
-
-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 da \param{timout}, o fintanto che non arrivi un
-segnale.\footnote{si tenga conto che questo segnale può anche essere 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.
-
-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 è:
-\begin{prototype}{aio.h}
- {int lio\_listio(int mode, struct aiocb * const list[], int nent, struct
- sigevent *sig)}
-
- Richiede l'esecuzione delle operazioni di I/O elencata da \param{list},
- secondo la modalità \param{mode}.
-
- \bodydesc{La funzione restituisce 0 in caso di successo, e -1 in caso di
- errore, nel qual caso \var{errno} assumerà uno dei valori:
- \begin{errlist}
- \item[\errcode{EAGAIN}] nessuna operazione è stata completata entro
- \param{timeout}.
- \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.
- \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
- \end{errlist}
- }
-\end{prototype}
-
-La funzione esegue la richiesta delle \param{nent} operazioni indicate nella
-lista \param{list} che deve contenere gli indirizzi di altrettanti
-\textit{control block} opportunamente inizializzati; in particolare 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.
-\item[\const{LIO\_NOP}] non si effettua nessuna 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}.
-
-
-\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_base_func}. 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 cap.~\ref{cha: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
-\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 \index{memoria~virtuale}
-che in maniera analoga a quanto avviene per le pagine che vengono salvate e
-rilette nella 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.
-
-Infatti, dato che l'accesso è fatto direttamente attraverso la
-\index{memoria~virtuale} 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 swap.
-
-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 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.
-
-L'interfaccia POSIX implementata da Linux prevede varie funzioni 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{functions}
-
- \headdecl{unistd.h}
- \headdecl{sys/mman.h}
-
- \funcdecl{void * mmap(void * start, size\_t length, int prot, int flags, int
- fd, off\_t offset)}
-
- Esegue la mappatura in memoria della sezione specificata del file \param{fd}.
-
- \bodydesc{La funzione restituisce il puntatore alla zona di memoria mappata
- in caso di successo, e \const{MAP\_FAILED} (-1) in caso di errore, nel
- qual caso \var{errno} assumerà uno dei valori:
- \begin{errlist}
- \item[\errcode{EBADF}] il file descriptor non è valido, e non si è usato
- \const{MAP\_ANONYMOUS}.
- \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{EINVAL}] i valori di \param{start}, \param{length} o
- \param{offset} non sono validi (o troppo grandi o non allineati sulla
- dimensione delle pagine).
- \item[\errcode{ETXTBSY}] si è impostato \const{MAP\_DENYWRITE} ma
- \param{fd} è aperto in scrittura.
- \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{ENOMEM}] non c'è memoria o si è superato il limite sul
- numero di mappature possibili.
- \item[\errcode{ENODEV}] il filesystem di \param{fd} non supporta il memory
- mapping.
- \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{ENFILE}] si è superato il limite del sistema sul numero di
- file aperti (vedi sez.~\ref{sec:sys_resource_limit}).
- \end{errlist}
- }
-\end{functions}
-
-La funzione richiede di mappare in memoria la sezione del file \param{fd} a
-partire da \param{offset} per \param{lenght} byte, preferibilmente
-all'indirizzo \param{start}. 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{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 \itindex{page~table} \textit{page
- table} la mappatura sulle pagine di memoria reale, ed le modalità di
- accesso (lettura, esecuzione, scrittura); una loro violazione causa quella
- che si chiama una \textit{segment violation}, e la relativa emissione del
- segnale \const{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.
-
-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}.
-
-\begin{table}[htb]
- \centering
- \footnotesize
- \begin{tabular}[c]{|l|p{11cm}|}
- \hline
- \textbf{Valore} & \textbf{Significato} \\
- \hline
- \hline
- \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\_SHARED} & I cambiamenti sulla memoria mappata vengono
- riportati sul file e saranno immediatamente
- visibili agli altri processi che mappano lo stesso
- file.\footnotemark Il file su disco però non sarà
- aggiornato fino alla chiamata di \func{msync} o
- \func{munmap}), e solo allora le modifiche saranno
- visibili per l'I/O convenzionale. Incompatibile
- con \const{MAP\_PRIVATE}.\\
- \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. Le modifiche sono mantenute attraverso
- il meccanismo del \textit{copy on
- write} \itindex{copy~on~write} e
- salvate su swap in caso di necessità. Non è
- specificato se i cambiamenti sul file originale
- vengano riportati sulla regione
- mappata. Incompatibile con \const{MAP\_SHARED}.\\
- \const{MAP\_DENYWRITE} & In Linux viene ignorato per evitare
- \textit{DoS} \itindex{Denial~of~Service~(DoS)}
- (veniva usato per segnalare che tentativi di
- scrittura sul file dovevano fallire con
- \errcode{ETXTBSY}).\\
- \const{MAP\_EXECUTABLE}& Ignorato.\\
- \const{MAP\_NORESERVE} & Si usa con \const{MAP\_PRIVATE}. Non riserva
- delle pagine di swap ad uso del meccanismo del
- \textit{copy on write} \itindex{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 \const{SIGSEGV}.\\
- \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
- mappate.\\
- \const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} stack. Indica
- che la mappatura deve essere effettuata con gli
- indirizzi crescenti verso il basso.\\
- \const{MAP\_ANONYMOUS} & La mappatura non è associata a nessun file. Gli
- argomenti \param{fd} e \param{offset} sono
- ignorati.\footnotemark\\
- \const{MAP\_ANON} & Sinonimo di \const{MAP\_ANONYMOUS}, deprecato.\\
- \const{MAP\_FILE} & Valore di compatibilità, ignorato.\\
- \const{MAP\_32BIT} & Esegue la mappatura sui primi 2GiB 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}.\\
- \const{MAP\_POPULATE} & Esegue il \itindex{prefaulting}
- \textit{prefaulting} delle pagine di memoria
- necessarie alla mappatura.\\
- \const{MAP\_NONBLOCK} & Esegue un \textit{prefaulting} più limitato che
- non causa I/O.\footnotemark\\
-% \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}
-
-
-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 \index{memoria~virtuale}
-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 (\const{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 \index{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.
-
-\footnotetext[68]{dato che tutti faranno riferimento alle stesse pagine di
- memoria.}
-
-\footnotetext[69]{l'uso di questo flag con \const{MAP\_SHARED} è stato
- implementato in Linux a partire dai kernel della serie 2.4.x; esso consente
- di creare segmenti di memoria condivisa e torneremo sul suo utilizzo in
- sez.~\ref{sec:ipc_mmap_anonymous}.}
-
-\footnotetext{questo flag ed il precedente \const{MAP\_POPULATE} sono stati
- introdotti nel kernel 2.5.46 insieme alla mappatura non lineare di cui
- parleremo più avanti.}
-
-\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
-verrà 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{lenght}, senza ottenere un \const{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à \const{SIGSEGV}, ma
-\const{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 pipe, socket e 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}