Altre correzioni di indicizzazioni. Introdotta mremap. Aggiornati i flag di
[gapil.git] / process.tex
index b19f7dd9eecee4e135d2c8479427c263481a1dbb..1166f5119bb17c853af906249cc922a7b9cc1592 100644 (file)
@@ -294,21 +294,21 @@ virtuale di tutti i processi che hanno detta funzione nel loro codice.
 
 La corrispondenza fra le pagine della \index{memoria~virtuale}memoria virtuale
 e quelle della memoria fisica della macchina viene gestita in maniera
-trasparente dall'hardware di gestione della memoria (la \textit{Memory
-  Management Unit} del processore).  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
-\textsl{paginazione}\index{paginazione} (o \textit{paging}), ed è uno dei
-compiti principali del kernel.
+trasparente dal kernel con l'ausilio dell'hardware di gestione della memoria
+(la \textit{Memory Management Unit} del processore).  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 \textsl{paginazione}\index{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 \textit{page
-  fault}\index{\textit{page~fault}}; l'hardware di gestione della memoria
-genera un'interruzione e passa il controllo al kernel il quale sospende il
-processo e si incarica di mettere in RAM la pagina richiesta (effettuando
-tutte le operazioni necessarie per reperire lo spazio necessario), per poi
-restituire il controllo al processo.
+  fault}\itindex{page~fault}; la gestione della memoria genera un'interruzione
+e passa il controllo al kernel il quale sospende il processo e si incarica di
+mettere in RAM la pagina richiesta (effettuando tutte le operazioni necessarie
+per reperire lo spazio necessario), per poi restituire il controllo al
+processo.
 
 Dal punto di vista di un processo questo meccanismo è completamente
 trasparente, e tutto avviene come se tutte le pagine fossero sempre
@@ -333,11 +333,11 @@ commette quando si 
 chiamato un \textit{segmentation fault}. Se si tenta cioè di leggere o
 scrivere da un indirizzo per il quale non esiste un'associazione della pagina
 virtuale, il kernel risponde al relativo \textit{page
-  fault}\index{\textit{page~fault}} mandando un segnale \const{SIGSEGV} al
-processo, che normalmente ne causa la terminazione immediata.
+  fault}\itindex{page~fault} mandando un segnale \const{SIGSEGV} al processo,
+che normalmente ne causa la terminazione immediata.
 
 È pertanto importante capire come viene strutturata \textsl{la memoria
-  virtuale}\index{\textit{page~fault}} di un processo. Essa viene divisa in
+  virtuale}\index{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:
@@ -555,7 +555,7 @@ tollerante nei confronti di piccoli errori come quello di chiamate doppie a
 Il problema più comune e più difficile da risolvere che si incontra con le
 routine di allocazione è quando non viene opportunamente liberata la memoria
 non più utilizzata, quello che in inglese viene chiamato \textit{memory
-  leak}\index{\textit{memory~leak}}, cioè una \textsl{perdita di memoria}.
+  leak}\itindex{memory~leak}, cioè una \textsl{perdita di memoria}.
 
 Un caso tipico che illustra il problema è quello in cui in una subroutine si
 alloca della memoria per uso locale senza liberarla prima di uscire. La
@@ -568,32 +568,33 @@ Il problema 
 momento, in corrispondenza ad una qualunque chiamata di \func{malloc}, che può
 essere in una sezione del codice che non ha alcuna relazione con la subroutine
 che contiene l'errore. Per questo motivo è sempre molto difficile trovare un
-\textit{memory leak}\index{\textit{memory~leak}}.
+\textit{memory leak}\itindex{memory~leak}.
 
 In C e C++ il problema è particolarmente sentito. In C++, per mezzo della
-programmazione ad oggetti, il problema dei \textit{memory leak} è notevolmente
-ridimensionato attraverso l'uso accurato di appositi oggetti come gli
-\textit{smartpointers}.  Questo però va a scapito delle prestazioni
-dell'applicazione in esecuzione.
-
-In altri linguaggi come il java e recentemente il C\# il problema non si pone
-nemmeno perché la gestione della memoria viene fatta totalmente in maniera
-automatica, ovvero il programmatore non deve minimamente preoccuparsi di
-liberare la memoria allocata precedentemente quando non serve più, poiché il
-framework gestisce automaticamente la cosiddetta \textit{garbage collection}.
-In tal caso, attraverso meccanismi simili a quelli del \textit{reference
-  counting}, quando una zona di memoria precedentemente allocata non è più
-riferita da nessuna parte del codice in esecuzione, può essere deallocata
-automaticamente in qualunque momento dall'infrastruttura.
-
-Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione
-(inoltre le applicazioni sviluppate con tali linguaggi di solito non sono
-eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria
-la presenza di una infrastruttura per la loro interpretazione e pertanto hanno
-di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni
-compilate direttamente).  Questo comporta però il problema della non
-predicibilità del momento in cui viene deallocata la memoria precedentemente
-allocata da un oggetto.
+programmazione ad oggetti, il problema dei \textit{memory
+  leak}\itindex{memory~leak} è notevolmente ridimensionato attraverso l'uso
+accurato di appositi oggetti come gli \textit{smartpointers}.  Questo però in
+genere va a scapito delle prestazioni dell'applicazione in esecuzione.
+
+% In altri linguaggi come il java e recentemente il C\# il problema non si pone
+% nemmeno perché la gestione della memoria viene fatta totalmente in maniera
+% automatica, ovvero il programmatore non deve minimamente preoccuparsi di
+% liberare la memoria allocata precedentemente quando non serve più, poiché
+% l'infrastruttura del linguaggio gestisce automaticamente la cosiddetta
+% \index{\textit{garbage~collection}}\textit{garbage collection}.  In tal caso,
+% attraverso meccanismi simili a quelli del \textit{reference counting}, quando
+% una zona di memoria precedentemente allocata non è più riferita da nessuna
+% parte del codice in esecuzione, può essere deallocata automaticamente in
+% qualunque momento dall'infrastruttura.
+
+% Anche questo va a scapito delle prestazioni dell'applicazione in esecuzione
+% (inoltre le applicazioni sviluppate con tali linguaggi di solito non sono
+% eseguibili compilati, come avviene invece per il C ed il C++, ed è necessaria
+% la presenza di una infrastruttura per la loro interpretazione e pertanto hanno
+% di per sé delle prestazioni più scadenti rispetto alle stesse applicazioni
+% compilate direttamente).  Questo comporta però il problema della non
+% predicibilità del momento in cui viene deallocata la memoria precedentemente
+% allocata da un oggetto.
 
 Per limitare l'impatto di questi problemi, e semplificare la ricerca di
 eventuali errori, l'implementazione delle routine di allocazione delle
@@ -613,10 +614,10 @@ molto complesse riguardo l'allocazione della memoria.
 \label{sec:proc_mem_sbrk_alloca}
 
 Una possibile alternativa all'uso di \func{malloc}, che non soffre dei
-problemi di \textit{memory leak}\index{\textit{memory~leak}} descritti in
-precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria
-nello heap usa il segmento di stack della funzione corrente. La sintassi è
-identica a quella di \func{malloc}, il suo prototipo è:
+problemi di \textit{memory leak}\itindex{memory~leak} descritti in precedenza,
+è la funzione \funcd{alloca}, che invece di allocare la memoria nello heap usa
+il segmento di stack della funzione corrente. La sintassi è identica a quella
+di \func{malloc}, il suo prototipo è:
 \begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
   Alloca \param{size} byte nello stack.
   
@@ -632,7 +633,7 @@ quindi non esiste un analogo della \func{free}) in quanto essa viene
 rilasciata automaticamente al ritorno della funzione.
 
 Come è evidente questa funzione ha molti vantaggi, anzitutto permette di
-evitare alla radice i problemi di memory leak\index{\textit{memory~leak}},
+evitare alla radice i problemi di \textit{memory leak}\itindex{memory~leak},
 dato che non serve più la deallocazione esplicita; inoltre la deallocazione
 automatica funziona anche quando si usa \func{longjmp} per uscire da una
 subroutine con un salto non locale da una funzione (vedi
@@ -709,6 +710,9 @@ standard descritte in precedenza, che sono costruite su di esse.
 % \subsection{La personalizzazione delle funzioni di allocazione} 
 % \label{sec:proc_mem_malloc_custom}
 
+% TODO documentare \func{madvise}
+% TODO documentare \func{mincore}
+% TODO documentare \func{mprotect} forse da mettere insieme a mmap
 
 \subsection{Il controllo della memoria virtuale}  
 \label{sec:proc_mem_lock}
@@ -750,42 +754,57 @@ motivi per cui si possono avere di queste necessit
   crittografia richiedono il blocco di alcune pagine di memoria.
 \end{itemize}
 
-\index{\textit{memory~locking}|(}
+\itindbeg{memory~locking} 
+
 Il meccanismo che previene la paginazione\index{paginazione} di parte della
 memoria virtuale di un processo è chiamato \textit{memory locking} (o
 \textsl{blocco della memoria}). Il blocco è sempre associato alle pagine della
 memoria virtuale del processo, e non al segmento reale di RAM su cui essa
-viene mantenuta.
-
-La regola è che se un segmento di RAM fa da supporto ad almeno una pagina
-bloccata allora esso viene escluso dal meccanismo della
+viene mantenuta.  La regola è che se un segmento di RAM fa da supporto ad
+almeno una pagina bloccata allora esso viene escluso dal meccanismo della
 paginazione\index{paginazione}. I blocchi non si accumulano, se si blocca due
 volte la stessa pagina non è necessario sbloccarla due volte, una pagina o è
-bloccata oppure no.
+bloccata oppure no. 
 
 Il \textit{memory lock} persiste fintanto che il processo che detiene la
 memoria bloccata non la sblocca. Chiaramente la terminazione del processo
 comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di
 tutti i suoi \textit{memory lock}.  Infine i \textit{memory lock} non sono
-ereditati dai processi figli.\footnote{ma siccome Linux usa il \textit{copy on
-    write} (vedi sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio
-  sono mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che
-  un figlio non scrive su un segmento, può usufruire del \textit{memory lock}
-  del padre.}
+ereditati dai processi figli,\footnote{ma siccome Linux usa il
+  \itindex{copy~on~write}\textit{copy on write} (vedi
+  sez.~\ref{sec:proc_fork}) gli indirizzi virtuali del figlio sono mantenuti
+  sullo stesso segmento di RAM del padre, quindi fintanto che un figlio non
+  scrive su un segmento, può usufruire del \textit{memory lock} del padre.} e
+vengono automaticamente rimossi se si pone in esecuzione un altro programma
+con \func{exec} (vedi sez.~\ref{sec:proc_exec}).
 
 Siccome la richiesta di un \textit{memory lock} da parte di un processo riduce
 la memoria fisica disponibile nel sistema, questo ha un evidente impatto su
-tutti gli altri processi, per cui solo un processo con i privilegi di
-amministratore (vedremo in sez.~\ref{sec:proc_perms} cosa significa) ha la
-capacità di bloccare una pagina.  Ogni processo può però sbloccare le pagine
-relative alla propria memoria.
+tutti gli altri processi, per cui fino al kernel 2.6.9 solo un processo con i
+privilegi opportuni (la \itindex{capability}\textit{capability}
+\const{CAP\_IPC\_LOCK}, vedi sez.~\ref{sec:proc_capabilities}) aveva la
+capacità di bloccare una pagina. 
 
 Il sistema pone dei limiti all'ammontare di memoria di un processo che può
 essere bloccata e al totale di memoria fisica che si può dedicare a questo, lo
 standard POSIX.1 richiede che sia definita in \file{unistd.h} la macro
 \macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il
-\textit{memory locking} e la costante \const{PAGESIZE} in \file{limits.h} per
-indicare la dimensione di una pagina in byte.
+\textit{memory locking}. Inoltre in alcuni sistemi è definita la costante
+\const{PAGE\_SIZE} in \file{limits.h} per indicare la dimensione di una pagina
+in byte.\footnote{con Linux questo non avviene e si deve ricorrere alla
+  funzione \func{getpagesize}, vedi sez.~\ref{sec:sys_memory_res}.} 
+
+
+Con il kernel 2.6.9 anche un processo normale può bloccare la propria
+memoria\footnote{la funzionalità è stata introdotta per non essere costretti a
+  dare privilegi eccessivi a programmi di crittografia, che necessitano di
+  questa funzionalità, ma che devono essere usati da utenti normali.} ma
+mentre un processo privilegiato non ha limiti sulla quantità di memoria che
+può bloccare, un processo normale è soggetto al limite della risorsa
+\const{RLIMIT\_MEMLOCK} (vedi sez.~\ref{sec:sys_resource_limit}). In generale
+poi ogni processo può sbloccare le pagine relative alla propria memoria, se
+però diversi processi bloccano la stessa pagina questa resterà bloccata
+fintanto che ci sarà almeno un processo che la blocca.
 
 Le funzioni per bloccare e sbloccare la paginazione\index{paginazione} di
 singole sezioni di memoria sono \funcd{mlock} e \funcd{munlock}; i loro
@@ -808,6 +827,8 @@ prototipi sono:
     corrispondono allo spazio di indirizzi del processo o si è ecceduto
     il numero massimo consentito di pagine bloccate.
   \item[\errcode{EINVAL}] \param{len} non è un valore positivo.
+  \item[\errcode{EPERM}] con un kernel successivo al 2.6.9 il processo non è
+    privilegiato e si un limite nullo per \const{RLIMIT\_MEMLOCK}.
   \end{errlist}
   e, per \func{mlock}, anche \errval{EPERM} quando il processo non ha i
   privilegi richiesti per l'operazione.}
@@ -817,7 +838,9 @@ Le due funzioni permettono rispettivamente di bloccare e sbloccare la
 paginazione\index{paginazione} per l'intervallo di memoria specificato dagli
 argomenti, che ne indicano nell'ordine l'indirizzo iniziale e la lunghezza.
 Tutte le pagine che contengono una parte dell'intervallo bloccato sono
-mantenute in RAM per tutta la durata del blocco.
+mantenute in RAM per tutta la durata del blocco.\footnote{con altri kernel si
+  può ottenere un errore di \errcode{EINVAL} se \param{addr} non è un multiplo
+  della dimensione delle pagine di memoria.}
 
 Altre due funzioni, \funcd{mlockall} e \funcd{munlockall}, consentono di
 bloccare genericamente la paginazione\index{paginazione} per l'intero spazio
@@ -831,8 +854,10 @@ di indirizzi di un processo.  I prototipi di queste funzioni sono:
   \funcdecl{int munlockall(void)}
   Sblocca la paginazione per lo spazio di indirizzi del processo corrente. 
   
-  \bodydesc{Codici di ritorno ed errori sono gli stessi di \func{mlock}
-    e \func{munlock}.}
+  \bodydesc{Codici di ritorno ed errori sono gli stessi di \func{mlock} e
+    \func{munlock}, con un kernel successivo al 2.6.9 l'uso di
+    func{munlockall} senza la la \itindex{capability}\textit{capability}
+\const{CAP\_IPC\_LOCK} genera un errore di \errcode{EPERM}.}
 \end{functions}
 
 L'argomento \param{flags} di \func{mlockall} permette di controllarne il
@@ -855,18 +880,19 @@ esempio limitandosi a tutte le pagine allocate a partire da un certo momento.
 In ogni caso un processo real-time che deve entrare in una sezione critica
 deve provvedere a riservare memoria sufficiente prima dell'ingresso, per
 scongiurare l'occorrenza di un eventuale \textit{page
-  fault}\index{\textit{page~fault}} causato dal meccanismo di \textit{copy on
-  write}\index{\textit{copy~on~write}}.  Infatti se nella sezione critica si
-va ad utilizzare memoria che non è ancora stata riportata in RAM si potrebbe
-avere un page fault durante l'esecuzione della stessa, con conseguente
-rallentamento (probabilmente inaccettabile) dei tempi di esecuzione.
+  fault}\itindex{page~fault} causato dal meccanismo di \textit{copy on
+  write}\itindex{copy~on~write}.  Infatti se nella sezione critica si va ad
+utilizzare memoria che non è ancora stata riportata in RAM si potrebbe avere
+un \itindex{page~fault}\textit{page fault} durante l'esecuzione della stessa,
+con conseguente rallentamento (probabilmente inaccettabile) dei tempi di
+esecuzione.
 
 In genere si ovvia a questa problematica chiamando una funzione che ha
 allocato una quantità sufficientemente ampia di variabili automatiche, in modo
 che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri
 che esse siano state effettivamente portate in memoria, ci si scrive sopra.
 \index{memoria~virtuale|)}
-\index{\textit{memory~locking}|)}
+\itindend{memory~locking}
 
 
 
@@ -1290,13 +1316,12 @@ nella programmazione normale.
 
 Talvolta però è necessario che la funzione possa restituire indietro alla
 funzione chiamante un valore relativo ad uno dei suoi argomenti.  Per far
-questo si usa il cosiddetto
-\index{\textit{value~result~argument}}\textit{value result argument}, si passa
-cioè, invece di una normale variabile, un puntatore alla stessa; vedremo
-alcuni esempi di questa modalità nelle funzioni che gestiscono i socket (in
-sez.~\ref{sec:TCP_functions}), in cui, per permettere al kernel di restituire
-informazioni sulle dimensioni delle strutture degli indirizzi utilizzate,
-viene usato questo meccanismo.
+questo si usa il cosiddetto \itindex{value~result~argument}\textit{value
+  result argument}, si passa cioè, invece di una normale variabile, un
+puntatore alla stessa; vedremo alcuni esempi di questa modalità nelle funzioni
+che gestiscono i socket (in sez.~\ref{sec:TCP_functions}), in cui, per
+permettere al kernel di restituire informazioni sulle dimensioni delle
+strutture degli indirizzi utilizzate, viene usato questo meccanismo.
 
 
 \subsection{Il passaggio di un numero variabile di argomenti}