-\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}
-
-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{PAGE\_SIZE}, 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}
-
-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 standard troveranno un contenuto
-del file aggiornato.
-
-\begin{table}[htb]
- \centering
- \footnotesize
- \begin{tabular}[c]{|l|l|}
- \hline
- \textbf{Valore} & \textbf{Significato} \\
- \hline
- \hline
- \const{MS\_ASYNC} & Richiede la sincronizzazione.\\
- \const{MS\_SYNC} & Attende che la sincronizzazione si eseguita.\\
- \const{MS\_INVALIDATE}& Richiede che le altre mappature dello stesso file
- siano invalidate.\\
- \hline
- \end{tabular}
- \caption{Le costanti che identificano i bit per la maschera binaria
- dell'argomento \param{flag} di \func{msync}.}
- \label{tab:file_mmap_rsync}
-\end{table}
-
-L'argomento \param{flag} è specificato come maschera binaria composta da un OR
-dei valori riportati in tab.~\ref{tab:file_mmap_rsync}, 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
-flag fa invalidare le pagine di cui si richiede la sincronizzazione per tutte
-le mappature dello stesso file, così che esse possano essere immediatamente
-aggiornate ai 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{functions}
- \headdecl{unistd.h}
- \headdecl{sys/mman.h}
-
- \funcdecl{int munmap(void *start, size\_t length)}
-
- Rilascia la mappatura sulla sezione di memoria specificata.
-
- \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}] l'intervallo specificato non ricade in una zona
- precedentemente mappata.
- \end{errlist}
- }
-\end{functions}
-
-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 è \funcd{mprotect} ed il suo prototipo è:
-\begin{functions}
-% \headdecl{unistd.h}
- \headdecl{sys/mman.h}
-
- \funcdecl{int mprotect(const void *addr, size\_t len, int prot)}
-
- Modifica le protezioni delle pagine di memoria comprese nell'intervallo
- specificato.
-
- \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}] il valore di \param{addr} non è valido o non è un
- multiplo di \const{PAGE\_SIZE}.
- \item[\errcode{EACCESS}] 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.
-% \item[\errcode{EFAULT}] si è specificato un indirizzo di memoria non
-% accessibile.
- \end{errlist}
- ed inoltre \errval{ENOMEM} ed \errval{EFAULT}.
- }
-\end{functions}
-
-
-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.