ad eseguire la mappatura in memoria di un file, è \funcd{mmap}; il suo
prototipo è:
-
\begin{funcproto}{
\fhead{unistd.h}
\fhead{sys/mman.h}
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 valore diverso da \val{NULL},
-in cui di rimette completamente al kernel la scelta dell'indirizzo, viene
+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.
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
+ 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 una \itindex{segment~violation}
\const{MAP\_GROWSDOWN} & Usato per gli \itindex{stack} \textit{stack}.
Indica che la mappatura deve essere effettuata
con gli indirizzi crescenti verso il basso.\\
- \const{MAP\_HUGETLB} & da trattare (dal 2.6.32).\\
+ \const{MAP\_HUGETLB} & Esegue la mappatura usando le cosiddette
+ ``\textit{huge pages}'' (dal 2.6.32).\\
\const{MAP\_LOCKED} & Se impostato impedisce lo swapping delle pagine
mappate (dal 2.5.37).\\
\const{MAP\_NONBLOCK} & Esegue un \textit{prefaulting} più limitato che
\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 \signal{SIGSEGV}.\\
+ 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\_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
+ il meccanismo del \textit{copy on write} e
salvate su swap in caso di necessità. Non è
specificato se i cambiamenti sul file originale
vengano riportati sulla regione
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 \itindex{prefaulting} \textit{prefaulting}. Questo viene di nuovo in aiuto
-per migliorare le prestazioni in certe condizioni di utilizzo del
-\textit{memory mapping}.
+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
-\index{memoria~virtuale} memoria virtuale è quello per cui la regione mappata
-viene aggiunta alla \itindex{page~table} \textit{page table} del processo, ma
-i dati verranno effettivamente utilizzati (si avrà cioè un
-\itindex{page~fault} \textit{page fault} che li trasferisce dal disco alla
-memoria) soltanto in corrispondenza dell'accesso a ciascuna delle pagine
-interessate dal \textit{memory mapping}.
+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 \itindex{page~fault} \textit{page
fault}, chiaramente se si sa in anticipo che il file verrà utilizzato
-immediatamente, è molto più efficiente eseguire un \itindex{prefaulting}
-\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}.
+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 \itindex{prefaulting}
-\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.}
+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,
\subsection{I concetti generali}
\label{sec:proc_mem_gen}
+\index{memoria~virtuale|(}
+
Ci sono vari modi in cui i sistemi operativi organizzano la memoria, ed i
dettagli di basso livello dipendono spesso in maniera diretta
dall'architettura dell'hardware, ma quello più tipico, usato dai sistemi
-unix-like come Linux è la cosiddetta \index{memoria~virtuale} \textsl{memoria
- virtuale} che consiste nell'assegnare ad ogni processo uno spazio virtuale
-di indirizzamento lineare, in cui gli indirizzi vanno da zero ad un qualche
-valore massimo.\footnote{nel caso di Linux fino al kernel 2.2 detto massimo
- era, per macchine a 32bit, di 2Gb. Con il kernel 2.4 ed il supporto per la
- \textit{high-memory} il limite è stato esteso anche per macchine a 32 bit.}
-
+unix-like come Linux è la cosiddetta \textsl{memoria virtuale} che consiste
+nell'assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare,
+in cui gli indirizzi vanno da zero ad un qualche valore massimo.\footnote{nel
+ caso di Linux fino al kernel 2.2 detto massimo era, per macchine a 32bit, di
+ 2Gb. Con il kernel 2.4 ed il supporto per la \textit{high-memory} il limite
+ è stato esteso anche per macchine a 32 bit.}
Come accennato nel cap.~\ref{cha:intro_unix} questo spazio di indirizzi è
virtuale e non corrisponde all'effettiva posizione dei dati nella RAM del
farà da supporto a tutte le pagine di memoria virtuale di tutti i processi che
hanno detta funzione nel loro codice.
-La corrispondenza fra le pagine della \index{memoria~virtuale} memoria
-virtuale di un processo e quelle della memoria fisica della macchina viene
-gestita in maniera trasparente dal kernel.\footnote{in genere con l'ausilio
- dell'hardware di gestione della memoria (la \textit{Memory Management Unit}
- del processore), con i kernel della serie 2.6 è comunque diventato possibile
- utilizzare Linux anche su architetture che non dispongono di una MMU.}
-Poiché in genere la memoria fisica è solo una piccola frazione della memoria
-virtuale, è necessario un meccanismo che permetta di trasferire le pagine che
-servono dal supporto su cui si trovano in memoria, eliminando quelle che non
-servono. Questo meccanismo è detto \index{paginazione} \textsl{paginazione}
-(o \textit{paging}), ed è uno dei compiti principali del kernel.
+La corrispondenza fra le pagine della memoria virtuale di un processo e quelle
+della memoria fisica della macchina viene gestita in maniera trasparente dal
+kernel.\footnote{in genere con l'ausilio dell'hardware di gestione della
+ memoria (la \textit{Memory Management Unit} del processore), con i kernel
+ della serie 2.6 è comunque diventato possibile utilizzare Linux anche su
+ architetture che non dispongono di una MMU.} Poiché in genere la memoria
+fisica è solo una piccola frazione della memoria virtuale, è necessario un
+meccanismo che permetta di trasferire le pagine che servono dal supporto su
+cui si trovano in memoria, eliminando quelle che non servono. Questo
+meccanismo è detto \index{paginazione} \textsl{paginazione} (o
+\textit{paging}), ed è uno dei compiti principali del kernel.
Quando un processo cerca di accedere ad una pagina che non è nella memoria
reale, avviene quello che viene chiamato un \itindex{page~fault} \textit{page
permettono di bloccare il meccanismo della \index{paginazione} paginazione e
mantenere fisse delle pagine in memoria (vedi sez.~\ref{sec:proc_mem_lock}).
+\index{memoria~virtuale|)}
\subsection{La struttura della memoria di un processo}
\label{sec:proc_mem_layout}
\itindex{page~fault} \textit{page fault} mandando un segnale \signal{SIGSEGV}
al processo, che normalmente ne causa la terminazione immediata.
-È pertanto importante capire come viene strutturata \index{memoria~virtuale}
-la memoria virtuale di un processo. Essa viene divisa in \textsl{segmenti},
-cioè un insieme contiguo di indirizzi virtuali ai quali il processo può
-accedere. Solitamente un programma C viene suddiviso nei seguenti segmenti:
+È pertanto importante capire come viene strutturata la memoria virtuale di un
+processo. Essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di
+indirizzi virtuali ai quali il processo può accedere. Solitamente un
+programma C viene suddiviso nei seguenti segmenti:
\begin{enumerate*}
\item Il \index{segmento!testo} segmento di testo o \textit{text segment}.
Contiene il codice del programma, delle funzioni di librerie da esso