Sistemato il memory locking
authorSimone Piccardi <piccardi@gnulinux.it>
Mon, 5 Nov 2001 18:52:06 +0000 (18:52 +0000)
committerSimone Piccardi <piccardi@gnulinux.it>
Mon, 5 Nov 2001 18:52:06 +0000 (18:52 +0000)
process.tex
prochand.tex

index a096d6a..e022c2e 100644 (file)
@@ -6,7 +6,7 @@ sistema unix alloca ed utilizza le risorse.  Questo capitolo tratter
 l'interfaccia base fra il sistema e i processi, su come vengono passati i
 parametri, come viene gestita e allocata la memoria, su come un processo può
 richiedere servizi al sistema, su cosa deve fare quando ha finito la sua
-esecuzione. Nella sezione finale acceneremo ad alcune problematiche generiche
+esecuzione. Nella sezione finale accenneremo ad alcune problematiche generiche
 di programmazione.
 
 In genere un programma viene eseguito quando un processo lo fa partire
@@ -460,7 +460,7 @@ quattro, i prototipi sono i seguenti:
 \funcdecl{void free(void *ptr)}
   Disalloca lo spazio di memoria puntato da \var{ptr}.
 
-  La funzione non ritorna nulla.
+  La funzione non ritorna nulla e non riporta errori.
 \end{functions}
 Il puntatore che le funzioni di allocazione ritornano è garantito essere
 sempre correttamente allineato per tutti i tipi di dati; ad esempio sulle
@@ -494,14 +494,16 @@ comporta come \func{malloc}\footnote{questo 
   sotto Linux}), ad esempio quando si deve far crescere la dimensione di un
 vettore; in questo caso se è disponibile dello spazio adiacente al precedente
 la funzione lo utilizza, altrimenti rialloca altrove un blocco della dimensione
-voluta copiandoci automaticamente il contenuto, lo spazio in più non viene
+voluta copiandoci automaticamente il contenuto, lo spazio aggiunto non viene
 inizializzato. 
 
-Il fatto che il blocco di memoria restituito da \func{realloc} possa
-cambiare comporta che si deve sempre riassegnare al puntatore passato per il
-ridimensionamento il valore di ritorno della funzione, e che non ci devono
-essere altri puntatori che puntino all'interno di un'area che si vuole
-ridimensionare.
+Si deve sempre avere ben presente il fatto che il blocco di memoria restituito
+da \func{realloc} può non essere una estensione di quello che gli si è passato
+come parametro; pertanto esso deve essere trattato allo stesso modo di una
+nuova allocazione; in particolare si dovrà \emph{sempre} eseguire la
+riassegnazione di \var{ptr} al valore di ritorno della funzione, e
+reinizializzare (o provvedere ad un adeguato aggiornamento qualora ancora
+servano) tutti gli altri puntatori al blocco di dati ridimensionato.
 
 Uno degli errori più comuni (specie se si ha a che fare con array di
 puntatori) è infatti quello di chiamare \func{free} più di una volta sullo
@@ -545,20 +547,20 @@ permettono di sostituire alle funzioni di libreria una propria versione (che
 può essere più o meno specializzata per il debugging).
 
 
-\subsection{La funzione \texttt{alloca}}  
+\subsection{La funzione \func{alloca}}  
 \label{sec:proc_mem_alloca}
 
-Una alternativa possibile all'uso di \texttt{malloc}, che non soffre del tipo
+Una alternativa possibile all'uso di \func{malloc}, che non soffre del tipo
 di problemi di memory leak descritti in precedenza è la funzione
-\texttt{alloca} che invece che allocare la memoria nello heap usa lo il
+\func{alloca} che invece che allocare la memoria nello heap usa lo il
 segmento di stack della funzione corrente. La sintassi è identica:
 \begin{prototype}{stdlib.h}{void *alloca(size\_t size)}
-  Alloca \texttt{size} byte nel segmento di stack della funzione chiamante.
+  Alloca \var{size} byte nel segmento di stack della funzione chiamante.
   La memoria non viene inizializzata.
 
   La funzione restituisce il puntatore alla zona di memoria allocata in caso
-  di successo e \texttt{NULL} in caso di fallimento, nel qual caso
-  \texttt{errno} viene settata a \texttt{ENOMEM}.
+  di successo e \macro{NULL} in caso di fallimento, nel qual caso
+  \var{errno} viene settata a \macro{ENOMEM}.
 \end{prototype}
 ma in questo caso non è più necessario liberare la memoria in quanto questa
 viene rilasciata automaticamente al ritorno della funzione.
@@ -571,33 +573,32 @@ usa \func{longjump} per uscire con un salto non locale da una funzione (vedi
 
 Un altro vantaggio e che in Linux la funzione è molto veloce e non viene
 sprecato spazio, infatti non è necessario gestire un pool di memoria da
-riservare e si evitano anche problemi di frammentazione.
+riservare e si evitano anche i problemi di frammentazione di quest'ultimo che
+comportano inefficienze sia nell'allocazione della memoria che nell'esecuzione
+della funzione.
 
-Gli svantaggi sono che la funzione non è disponibile su tutti gli unix, quando
-non è possibile aumentare le dimensioni dello stack una volta chiamata una
-funzione e quindi l'uso limita la portabilità dei programmi, inoltre se si
-cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma un
-segnale di \textit{segment violation} analogo a quello che si avrebbe da una
-ricorsione infinita.
+Gli svantaggi sono che questa funzione non è disponibile su tutti gli unix,
+(quando non è possibile aumentare le dimensioni dello stack una volta chiamata
+una funzione) e quindi l'uso limita la portabilità dei programmi, inoltre se
+si cerca di allocare troppa memoria non si ottiene un messaggio di errore, ma
+un segnale di \textit{segment violation} analogo a quello che si avrebbe da
+una ricorsione infinita.
 
 Inoltre non è chiaramente possibile usare questa funzione per allocare memoria
 che deve poi essere usata anche al di fuori della funzione in cui questa viene
 chiamata, in quanto all'uscita dalla funzione lo spazio allocato diventerebbe
 libero, e potrebbe essere sovrascritto all'invocazione di nuove funzioni con
-conseguenze imprevedibili. 
+conseguenze imprevedibili. Questo è lo stesso problema potenziale che si può
+avere con le variabili automatiche, su cui torneremo in
+\secref{sec:proc_auto_var}.
 
-Questo è lo stesso problema potenziale che si può avere con le variabili
-automatiche; un errore comune infatti è quello di restituire al chiamante un
-puntatore ad una di queste variabili, che sarà automaticamente distrutta
-all'uscita della funzione, con gli stessi problemi appena citati per
-\func{alloca}.
 
 \subsection{Le funzioni \func{brk} e \func{sbrk}}  
 \label{sec:proc_mem_sbrk}
 
 L'uso di queste funzioni è necessario solo quando si voglia accedere alle
 analoghe system call a cui fanno da interfaccia (ad esempio per implementare
-una propria versione di \func{malloc}. Le  funzione sono:
+una propria versione di \func{malloc}. Le funzioni sono:
 \begin{prototype}{unistd.h}{int *brk(void end\_data\_segment)}
   Sposta la fine del segmento dei dati all'indirizzo specificato da
   \var{end\_data\_segment}.
@@ -633,11 +634,11 @@ maniera trasparente ai processi, decidendo quando rimuovere pagine dalla
 memoria per metterle nello swap sulla base dell'utilizzo corrente da parte dei
 vari processi. 
 
-Nell'uso comune un processo non deve preoccuparsi di tutto ciò in quanto il
+Nell'uso comune un processo non deve preoccuparsi di tutto ciò, in quanto il
 meccanismo della paginazione riporta in RAM, ed in maniera trasparente, tutte
 le pagine che gli occorrono; esistono però esigenze particolari in cui non si
-vuole che il meccanismo dello \textit{swapping}, in generale i motivi per cui
-si possono avere queste necessità sono sostanzialmente due:
+vuole che si attivi il meccanismo dello \textit{swapping}, in generale i
+motivi per cui si possono avere queste necessità sono sostanzialmente due:
 \begin{itemize}
 \item La velocità. Il processo della paginazione è trasparente solo se il
   programma in esecuzione se non è sensibile al tempo che occorre a riportare
@@ -654,11 +655,12 @@ si possono avere queste necessit
   
 \item La sicurezza. Se si tengono password o chiavi in memoria queste possono
   essere portate su disco dal meccanismo della paginazione, questo rende più
-  lungo il periodo di tempo in cui i segreti sono presenti in chiaro, e
-  complessa la loro cancellazione (in genere è possibile cancellare della RAM
-  ma altrettanto non vale per il disco su cui la pagina contenente i segreti
-  può essere stata salvata). Per questo motivo programmi di crittografia
-  richiedono il blocco di alcune pagine di memoria.
+  lungo il periodo di tempo in cui i segreti sono presenti in chiaro e più
+  complessa la loro cancellazione (ad un processo è possibile cancellare la
+  memoria su cui scrive le sue variabili, ma non può toccare lo spazio disco
+  su cui la pagina contenente i segreti può essere stata salvata). Per questo
+  motivo di solito i programmi di crittografia richiedono il blocco di alcune
+  pagine di memoria.
 \end{itemize}
 
 Il meccanismo che previene la paginazione di parte della memoria virtuale di
@@ -674,50 +676,101 @@ sbloccarla due volte, una pagina o 
 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 \textit{memory lock}.
+tutti i suoi \textit{memory lock}.
 
 I \textit{memory lock} non sono ereditati dai processi figli\footnote{ma
   siccome Linux usa il copy on write 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 dei memory lock del padre}.
-Siccome la presenza di \textit{memory lock} ha un impatto sugli altri processi
-solo l'amministratore ha la capacità di bloccare una pagina; ogni processo
-però può sbloccare le sue pagine. Il sistema pone dei limiti all'ammontare di
-memoria di un processo che può essere bloccata e al totale di memoria fisica
-che può dedicare a questo.
+Siccome la presenza di un \textit{memory lock} riduce la memoria disponibile
+al sistema con un impatto su tutti gli altri processi, solo l'amministratore ha
+la capacità di bloccare una pagina. Ogni processo però può sbloccare le sue
+pagine. 
+
+
+Il sistema pone dei limiti all'ammontare di memoria di un processo che può
+essere bloccata e al totale di memoria fisica che può dedicare a questo, lo
+standard POSIX.1 richiede che sia definita in \file{unistd.h} la costante
+\macro{\_POSIX\_MEMLOCK\_RANGE} per indicare la capacità di eseguire il
+\textit{memory locking} e la costante \macro{PAGESIZE} in \file{limits.h} per
+indicare la dimensione di una pagina in byte.
+
 
 Le funzioni per bloccare e sbloccare singole sezioni di memoria sono
 \func{mlock} e \func{munlock}; i loro prototipi sono:
-
 \begin{functions}
-\headdecl{stdlib.h}
-\funcdecl{void *calloc(size\_t size)}
-  Alloca \var{size} byte nello heap. La memoria viene inizializzata a 0.
+  \headdecl{sys/mman.h} 
+
+  \funcdecl{int mlock(const void *addr, size\_t len)}
+  Blocca la paginazione per l'intervallo di memoria da \var{addr} per
+  \var{len} byte. Tutte le pagine che contengono una parte dell'intervallo
+  sono mantenute in RAM per tutta la durata del blocco.
+
+  La funzione ritorna 0 in caso di successo e -1 in caso di errore, nel qual
+  caso \var{errno} è settata ad uno dei valori seguenti:
+  \begin{errlist}
+  \item \macro{ENOMEM} alcuni indirizzi dell'intervallo specificato non
+    corripondono allo spazio di indirizzi del processo o si è ecceduto il
+    numero massimo consentito di pagine bloccate.
+  \item \macro{EPERM} il processo non ha i privilegi richiesti per
+    l'operazione. 
+  \item \macro{EINVAL} \var{len} non è un valore positivo.
+  \end{errlist}
   
-  La funzione restituisce il puntatore alla zona di memoria allocata in caso
-  di successo e \macro{NULL} in caso di fallimento, nel qual caso
-  \var{errno} viene settata a \macro{ENOMEM}.
-\funcdecl{void *malloc(size\_t size)}
+  \funcdecl{int munlock(const void *addr, size\_t len)}
   Alloca \var{size} byte nello heap. La memoria non viene inizializzata.
 
-  La funzione restituisce il puntatore alla zona di memoria allocata in caso
-  di successo e \macro{NULL} in caso di fallimento, nel qual caso
-  \var{errno} viene settata a \macro{ENOMEM}.
-\funcdecl{void *realloc(void *ptr, size\_t size)}
-  Cambia la dimensione del blocco allocato all'indirizzo \var{ptr}
-  portandola a \var{size}.
+  Sblocca l'intervallo di memoria da \var{addr} per \var{len} byte.  La
+  funzione ritorna 0 in caso di successo e -1 in caso di errore, nel qual caso
+  \var{errno} è settata ad uno dei valori seguenti:
+  \begin{errlist}
+  \item \macro{ENOMEM} alcuni indirizzi dell'intervallo specificato non
+    corripondono allo spazio di indirizzi del processo.
+  \item \macro{EINVAL} \var{len} non è un valore positivo.
+  \end{errlist}
+\end{functions}
 
-  La funzione restituisce il puntatore alla zona di memoria allocata in caso
-  di successo e \macro{NULL} in caso di fallimento, nel qual caso
-  \var{errno} viene settata a \macro{ENOMEM}.
-\funcdecl{void free(void *ptr)}
-  Disalloca lo spazio di memoria puntato da \var{ptr}.
+Altre due funzioni, \func{mlockall} e \func{munlockall}, consentono di
+bloccare genericamente lo spazio di indirizzi di un processo.  I prototipi di
+queste funzioni sono:
 
-  La funzione non ritorna nulla.
-\end{functions}
+\begin{functions}
+  \headdecl{sys/mman.h} 
 
+  \funcdecl{int mlockall(int flags)}
+  Blocca la paginazione per lo spazio di indirizzi del processo corrente. 
+  
+  Codici di ritorno ed errori sono gli stessi di \func{mlock}.
 
+  \funcdecl{int munlockall(void)}
+  Sblocca la paginazione per lo spazio di indirizzi del processo corrente. 
+  
+  Codici di ritorno ed errori sono gli stessi di \func{munlock}.
+\end{functions}
 
+Il parametro \var{flags} di \func{mlockall} permette di controllarne il
+comportamento; esso può essere specificato come l'OR aritmetico delle due
+costanti: 
+\begin{description*}
+\item[\macro{MCL\_CURRENT}] blocca tutte le pagine correntemente mappate nello
+  spazio di indirizzi del processo.
+\item[\macro{MCL\_FUTURE}] blocca tutte le pagine che saranno mappate nello
+  spazio di indirizzi del processo.
+\end{description*}
+
+Con \func{mlockall} si può bloccare tutte le pagine mappate nello spazio di
+indirizzi del processo, sia che comprendano il segmento di testi, di dati, lo
+stack e lo heap e pure le funzioni di libreria chiamate, i file mappati in
+memoria, i dati del kernel mappati in user space, la memoria condivisa.  L'uso
+dei flag permette di selezionare con maggior finezza le pagine da bloccare, ad
+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, in genere
+questo si fa chiamando una funzione che ha allocato una quantità sufficiente
+ampia di variabili automatiche, in modo che esse vengano mappate in RAM dallo
+stack e poi ci scrive sopra, per scongiurare in partenza un eventuale page
+fault causato dal meccanismo di copy on write.
 
 
 \section{La gestione di parametri e opzioni}
@@ -848,7 +901,7 @@ comando.
 Anzitutto si può notare che si è anzitutto (\texttt{\small 1}) disabilitata la
 stampa di messaggi di errore per opzioni non riconosciute, per poi passare al
 ciclo per la verifica delle opzioni (\texttt{\small 2-27}); per ciascuna delle
-opioni possibili si è poi provveduto ad una opportuna azione, ad esempio per
+opzioni possibili si è poi provveduto ad una opportuna azione, ad esempio per
 le tre opzioni che prevedono un parametro si è effettuata la decodifica del
 medesimo, il cui indirizzo è contenuto nella variabile \var{optarg},
 avvalorando la relativa variabile (\texttt{\small 12-14}, \texttt{\small
@@ -953,9 +1006,9 @@ entit
 
 Una delle caratteristiche standard del C è che le variabili vengono passate
 alle subroutine attraverso un meccanismo che viene chiamato \textit{by value}
-(diverso ad esempio da quanto avviene con il Fortran, dove le variabli sono
-passate, come suol dirsi, \textit{by reference}, o dal C++ dove la modalità del
-passaggio può essere controllata con l'operatore \cmd{\&}). 
+(diverso ad esempio da quanto avviene con il Fortran, dove le variabili sono
+passate, come suol dirsi, \textit{by reference}, o dal C++ dove la modalità
+del passaggio può essere controllata con l'operatore \cmd{\&}).
 
 Il passaggio di una variabile \textit{by value} significa che in realtà quello
 che viene passato alla subroutine è una copia del valore attuale di quella
index e6913ed..f81dcc9 100644 (file)
@@ -17,7 +17,7 @@ problematiche generiche della programmazione in ambiente multitasking.
 \label{sec:proc_gen}
 
 Partiremo con una introduzione generale ai concetti che stanno alla base della
-gestione dei processi in un sitema unix-like. Introdurremo in questa sezione
+gestione dei processi in un sistema unix-like. Introdurremo in questa sezione
 l'architettura della gestione dei processi e le sue principali
 caratteristiche, e daremo una panoramica sull'uso delle principali funzioni
 per la gestione dei processi.
@@ -219,7 +219,7 @@ Oltre al \acr{pid} e al \acr{ppid}, e a quelli usati per il controllo di
 sessione, ad ogni processo sono associati altri identificatori, usati per il
 controllo di accesso, che servono per determinare se il processo può o meno
 eseguire le operazioni richieste, a seconda dei privilegi e dell'identità di
-chi lo ha posto in esecuzione; su questi torneremo in dettaglii più avanti in
+chi lo ha posto in esecuzione; su questi torneremo in dettagli più avanti in
 \secref{sec:proc_perm}.
 
 
@@ -1332,7 +1332,7 @@ il programma che si 
 settati (il significato di questi bit è affrontato in dettaglio in
 \secref{sec:file_suid_sgid}). In questo caso essi saranno settati all'utente e
 al gruppo proprietari del file; questo consente, per programmi in cui ci sia
-necessità, di dare a qualunquee utente normale privilegi o permessi di
+necessità, di dare a qualunque utente normale privilegi o permessi di
 un'altro (o dell'amministratore).
 
 Come nel caso del \acr{pid} e del \acr{ppid} tutti questi identificatori
@@ -1397,10 +1397,10 @@ di utente e gruppo associati dal kernel ad ogni processo, 
 \subsection{Le funzioni \func{setuid} e \func{setgid}}
 \label{sec:proc_setuid}
 
-Le due funzioni che venfono usate per cambiare identità (cioè utente e gruppo
+Le due funzioni che vengono usate per cambiare identità (cioè utente e gruppo
 di appartenenza) ad un processo sono rispettivamente \func{setuid} e
 \func{setgid}; come accennato in \secref{sec:proc_user_group} in Linux esse
-seguono la sematica POSIX che prevede l'esistenza di \textit{saved user id} e
+seguono la semantica POSIX che prevede l'esistenza di \textit{saved user id} e
 \textit{saved group id}; i loro prototipi sono:
 
 \begin{functions}
@@ -1426,7 +1426,7 @@ delle funzioni che tratteremo in questa sezione.
 
 L'effetto della chiamata è diverso a seconda dei privilegi del processo; se
 l'\textit{effective user id} è zero (cioè è quello dell'amministratore di
-sistema) allora tutti gli identificatatori (\textit{real}, \textit{effective}
+sistema) allora tutti gli identificatori (\textit{real}, \textit{effective}
 e \textit{saved}) vengono settati al valore specificato da \var{uid},
 altrimenti viene settato solo l'\textit{effective user id}, e soltanto se il
 valore specificato corrisponde o al \textit{real user id} o al \textit{saved
@@ -1441,7 +1441,7 @@ eventualmente tornare indietro.
 Come esempio per chiarire dell'uso di queste funzioni prediamo quello con cui
 viene gestito l'accesso al file \file{/var/log/utmp}.  In questo file viene
 registrato chi sta usando il sistema al momento corrente; chiaramente non può
-essere lasciato aperto in scrittura a qualunque utente, che protrebbe
+essere lasciato aperto in scrittura a qualunque utente, che potrebbe
 falsificare la registrazione. Per questo motivo questo file (e l'analogo
 \file{/var/log/wtmp} su cui vengono registrati login e logout) appartengono ad
 un gruppo dedicato (\acr{utmp}) ed i programmi che devono accedervi (ad
@@ -1519,7 +1519,7 @@ Le funzioni restituiscono 0 in caso di successo e -1 in caso di fallimento:
 l'unico errore possibile è \macro{EPERM}. 
 \end{functions}
 
-I processi non privileguiati possono settare i \textit{real id} soltanto ai
+I processi non privilegiati possono settare i \textit{real id} soltanto ai
 valori dei loro \textit{effective id} o \textit{real id} e gli
 \textit{effective id} ai valori dei loro \textit{real id}, \textit{effective
   id} o \textit{saved id}; valori diversi comportano il fallimento della
@@ -1578,9 +1578,9 @@ l'unico errore possibile 
 
 I processi non privilegiati possono cambiare uno qualunque degli
 identificatori usando uno qualunque dei valori correnti di \textit{real id},
-\textit{effective id} o \textit{saved id}, l'ammnistratore può specificare i
+\textit{effective id} o \textit{saved id}, l'amministratore può specificare i
 valori che vuole; un valore di -1 per un qualunque parametro lascia inalterato
-l'dentificatore corrispondente.
+l'identificatore corrispondente.
 
 
 
@@ -1634,7 +1634,7 @@ ha temporaneamente assunto l'identit
 quelli originari per quanto riguarda tutti gli altri controlli di accesso.
 
 Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid}
-e \func{setfsgid}, ovviamenete sono specifiche di Linux e non devono essere
+e \func{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
 usate se si intendono scrivere programmi portabili; i loro prototipi sono:
 
 \begin{functions}
@@ -1683,7 +1683,7 @@ quando si ha la certezza che, qualora essa venga effettuata, tutti i passaggi
 che devono essere compiuti per realizzarla verranno eseguiti senza possibilità
 di interruzione in una fase intermedia.
 
-In un ambiente multitasking il concetto è esseziale, dato che un processo può
+In un ambiente multitasking il concetto è essenziale, dato che un processo può
 essere interrotto in qualunque momento dal kernel che mette in esecuzione un
 altro processo o dalla ricezione di un segnale; occorre pertanto essere
 accorti nei confronti delle possibili \textit{race condition} (vedi
@@ -1736,7 +1736,7 @@ di eseguire atomicamente le operazioni necessarie, occorre che le risorse
 condivise siano opportunamente protette da meccanismi di sincronizzazione
 (torneremo su queste problematiche di questo tipo in \secref{sec:ipc_semaph}).
 
-Un caso particolare di \textit{race condition} sono poi i cosidetti
+Un caso particolare di \textit{race condition} sono poi i cosiddetti
 \textit{deadlock}; l'esempio tipico è quello di un flag di ``occupazione'' che
 viene rilasciato da un evento asincrono fra il controllo (in cui viene trovato
 occupato) e la successiva messa in attesa, attesa che a questo punto diventerà