+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. Il meccanismo è
+illustrato in fig.~\ref{fig:file_mmap_layout}, una sezione del file viene
+riportata direttamente nello spazio degli indirizzi del programma. Tutte le
+operazioni su questa zona verranno riportate indietro sul file dal meccanismo
+della memoria virtuale\index{memoria~virtuale} che trasferirà il contenuto di
+quel segmento sul file invece che nella swap, per cui si può parlare tanto di
+file mappato in memoria, quanto di memoria mappata su file.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[width=7.cm]{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}
+
+Tutto questo 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, ma 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 memoria
+virtuale,\index{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 prevede varie funzioni per la gestione del \textit{memory mapped
+ I/O}, la prima di queste è \funcd{mmap}, che serve ad eseguire la mappatura
+in memoria di un file; 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 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.
+ \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.
+ \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 \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_flag}; 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{10cm}|}
+ \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{unmap}), 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}\index{\textit{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}\index{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}\index{\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 \const{SIGSEGV}. \\
+ \const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
+ mappate. \\
+ \const{MAP\_GROWSDOWN} & Usato per gli 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à, deprecato.\\
+ \hline
+ \end{tabular}
+ \caption{Valori possibili dell'argomento \param{flag} di \func{mmap}.}
+ \label{tab:file_mmap_flag}
+\end{table}
+
+\footnotetext{Dato che tutti faranno riferimento alle stesse pagine di
+ memoria.}
+\footnotetext{L'uso di questo flag con \const{MAP\_SHARED} è
+ stato implementato in Linux a partire dai kernel della serie 2.4.x.}
+
+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 basato sul meccanismo della memoria
+virtuale.\index{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.
+
+\begin{figure}[!htb]
+ \centering
+ \includegraphics[width=10cm]{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}
+
+È 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. 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.
+
+\begin{figure}[htb]
+ \centering
+ \includegraphics[width=10cm]{img/mmap_exceed}
+ \caption{Schema della mappatura in memoria di file di dimensioni inferiori
+ alla lunghezza richiesta.}
+ \label{fig:file_mmap_exceed}
+\end{figure}
+
+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.
+
+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 \index{memoria~virtuale}memoria virtuale, occorre essere
+consapevoli delle interazioni che possono esserci con operazioni effettuate
+con l'interfaccia standard dei file di cap.~\ref{cha: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 standard 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 file attraverso
+l'interfaccia standard, quando lo si è mappato in memoria, è invece possibile
+usare l'interfaccia standard 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{functions}
+ \headdecl{unistd.h}
+ \headdecl{sys/mman.h}
+
+ \funcdecl{int msync(const void *start, size\_t length, int flags)}
+
+ Sincronizza i contenuti di una sezione di un file mappato in memoria.
+
+ \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{EINVAL}] O \param{start} non è multiplo di \const{PAGESIZE},
+ o si è specificato un valore non valido per \param{flags}.
+ \item[\errcode{EFAULT}] L'intervallo specificato non ricade in una zona
+ precedentemente mappata.
+ \end{errlist}
+ }
+\end{functions}