From: Simone Piccardi Date: Fri, 4 Sep 2015 19:57:20 +0000 (+0000) Subject: Modifiche fino a madvise X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=dfc23dbc3caad01544e73d2488f8490d9260ebae Modifiche fino a madvise --- diff --git a/fileadv.tex b/fileadv.tex index e99b81b..aeced0f 100644 --- a/fileadv.tex +++ b/fileadv.tex @@ -1227,14 +1227,14 @@ una variabile locale, in modo da mantenere l'aderenza allo standard POSIX che richiede che il valore di \param{timeout} non sia modificato. Rispetto a \func{select} la nuova funzione prende un argomento -aggiuntivo \param{sigmask}, un puntatore ad una \index{maschera~dei~segnali} -maschera di segnali (si veda sez.~\ref{sec:sig_sigmask}). Nell'esecuzione la -maschera dei segnali corrente viene sostituita da quella così indicata -immediatamente prima di eseguire l'attesa, e viene poi ripristinata al ritorno -della funzione. L'uso di \param{sigmask} è stato introdotto allo scopo di -prevenire possibili \textit{race condition} \itindex{race~condition} quando -oltre alla presenza di dati sui file descriptor come nella \func{select} -ordinaria, ci si deve porre in attesa anche dell'arrivo di un segnale. +aggiuntivo \param{sigmask}, un puntatore ad una maschera di segnali (si veda +sez.~\ref{sec:sig_sigmask}). Nell'esecuzione la maschera dei segnali corrente +viene sostituita da quella così indicata immediatamente prima di eseguire +l'attesa, e viene poi ripristinata al ritorno della funzione. L'uso +di \param{sigmask} è stato introdotto allo scopo di prevenire possibili +\textit{race condition} \itindex{race~condition} quando oltre alla presenza di +dati sui file descriptor come nella \func{select} ordinaria, ci si deve porre +in attesa anche dell'arrivo di un segnale. Come abbiamo visto in sez.~\ref{sec:sig_example} la tecnica classica per rilevare l'arrivo di un segnale è quella di utilizzare il gestore per @@ -1285,9 +1285,9 @@ Nello sviluppo di System V, invece di utilizzare l'interfaccia di \func{select}, che è una estensione tipica di BSD, è stata introdotta una interfaccia completamente diversa, basata sulla funzione di sistema \funcd{poll},\footnote{la funzione è prevista dallo standard XPG4, ed è stata - introdotta in Linux come system call a partire dal kernel 2.1.23 ed inserita - nelle \acr{libc} 5.4.28, originariamente l'argomento \param{nfds} era di - tipo \ctyp{unsigned int}, la funzione è stata inserita nello standard + introdotta in Linux come \textit{system call} a partire dal kernel 2.1.23 ed + inserita nelle \acr{libc} 5.4.28, originariamente l'argomento \param{nfds} + era di tipo \ctyp{unsigned int}, la funzione è stata inserita nello standard POSIX.1-2001 in cui è stato introdotto il tipo nativo \type{nfds\_t}.} il cui prototipo è: @@ -1480,12 +1480,11 @@ ed inoltre \errval{EFAULT} e \errval{ENOMEM} nel loro significato generico. \end{funcproto} La funzione ha lo stesso comportamento di \func{poll}, solo che si può -specificare, con l'argomento \param{sigmask}, il puntatore ad una -\index{maschera~dei~segnali} maschera di segnali; questa sarà la maschera -utilizzata per tutto il tempo che la funzione resterà in attesa, all'uscita -viene ripristinata la maschera originale. L'uso di questa funzione è cioè -equivalente, come illustrato nella pagina di manuale, all'esecuzione atomica -del seguente codice: +specificare, con l'argomento \param{sigmask}, il puntatore ad una maschera di +segnali; questa sarà la maschera utilizzata per tutto il tempo che la funzione +resterà in attesa, all'uscita viene ripristinata la maschera originale. L'uso +di questa funzione è cioè equivalente, come illustrato nella pagina di +manuale, all'esecuzione atomica del seguente codice: \includecodesnip{listati/ppoll_means.c} Eccetto per \param{timeout}, che come per \func{pselect} deve essere un @@ -1965,12 +1964,11 @@ Come già per \func{select} e \func{poll} anche per l'interfaccia di contemporaneamente. Valgono le osservazioni fatte in sez.~\ref{sec:file_select}, e per poterlo fare di nuovo è necessaria una variante della funzione di attesa che consenta di reimpostare all'uscita una -\index{maschera~dei~segnali} maschera di segnali, analoga alle estensioni -\func{pselect} e \func{ppoll} che abbiamo visto in precedenza per -\func{select} e \func{poll}. In questo caso la funzione di sistema si chiama -\funcd{epoll\_pwait}\footnote{la funzione è stata introdotta a partire dal - kernel 2.6.19, ed è come tutta l'interfaccia di \textit{epoll}, specifica di - Linux.} ed il suo prototipo è: +maschera di segnali, analoga alle estensioni \func{pselect} e \func{ppoll} che +abbiamo visto in precedenza per \func{select} e \func{poll}. In questo caso la +funzione di sistema si chiama \funcd{epoll\_pwait}\footnote{la funzione è + stata introdotta a partire dal kernel 2.6.19, ed è, come tutta l'interfaccia + di \textit{epoll}, specifica di Linux.} ed il suo prototipo è: \begin{funcproto}{ \fhead{sys/epoll.h} @@ -1989,10 +1987,10 @@ variante della funzione di attesa che consenta di reimpostare all'uscita una \end{funcproto} La funzione è del tutto analoga \funcd{epoll\_wait}, soltanto che alla sua -uscita viene ripristinata la \index{maschera~dei~segnali} maschera di segnali -originale, sostituita durante l'esecuzione da quella impostata con -l'argomento \param{sigmask}; in sostanza la chiamata a questa funzione è -equivalente al seguente codice, eseguito però in maniera atomica: +uscita viene ripristinata la maschera di segnali originale, sostituita durante +l'esecuzione da quella impostata con l'argomento \param{sigmask}; in sostanza +la chiamata a questa funzione è equivalente al seguente codice, eseguito però +in maniera atomica: \includecodesnip{listati/epoll_pwait_means.c} Si tenga presente che come le precedenti funzioni di \textit{I/O multiplexing} @@ -2081,8 +2079,8 @@ tramite file descriptor è \funcd{signalfd},\footnote{in realtà quella versione, \funcm{signalfd4}, introdotta con il kernel 2.6.27 e che è quella che viene sempre usata a partire dalle \acr{glibc} 2.9, che prende un argomento aggiuntivo \code{size\_t sizemask} che indica la dimensione della - \index{maschera~dei~segnali} maschera dei segnali, il cui valore viene - impostato automaticamente dalle \acr{glibc}.} il cui prototipo è: + maschera dei segnali, il cui valore viene impostato automaticamente dalle + \acr{glibc}.} il cui prototipo è: \begin{funcproto}{ \fhead{sys/signalfd.h} @@ -2120,13 +2118,13 @@ con \param{fd}, in caso di errore invece verrà restituito $-1$. L'elenco dei segnali che si vogliono gestire con \func{signalfd} deve essere specificato tramite l'argomento \param{mask}. Questo deve essere passato come -puntatore ad una \index{maschera~dei~segnali} maschera di segnali creata con -l'uso delle apposite macro già illustrate in sez.~\ref{sec:sig_sigset}. La -maschera deve indicare su quali segnali si intende operare con -\func{signalfd}; l'elenco può essere modificato con una successiva chiamata a -\func{signalfd}. Dato che \signal{SIGKILL} e \signal{SIGSTOP} non possono -essere intercettati (e non prevedono neanche la possibilità di un gestore) un -loro inserimento nella maschera verrà ignorato senza generare errori. +puntatore ad una maschera di segnali creata con l'uso delle apposite macro già +illustrate in sez.~\ref{sec:sig_sigset}. La maschera deve indicare su quali +segnali si intende operare con \func{signalfd}; l'elenco può essere modificato +con una successiva chiamata a \func{signalfd}. Dato che \signal{SIGKILL} e +\signal{SIGSTOP} non possono essere intercettati (e non prevedono neanche la +possibilità di un gestore) un loro inserimento nella maschera verrà ignorato +senza generare errori. L'argomento \param{flags} consente di impostare direttamente in fase di creazione due flag per il file descriptor analoghi a quelli che si possono @@ -2285,13 +2283,13 @@ Il primo passo (\texttt{\small 19-20}) è la creazione di un file descriptor quello che useremo per il controllo degli altri. É poi necessario disabilitare la ricezione dei segnali (nel caso \signal{SIGINT}, \signal{SIGQUIT} e \signal{SIGTERM}) per i quali si vuole la notifica tramite -file descriptor. Per questo prima li si inseriscono (\texttt{\small 22-25}) -in una \index{maschera~dei~segnali} maschera di segnali \texttt{sigmask} che -useremo con (\texttt{\small 26}) \func{sigprocmask} per disabilitarli. Con la -stessa maschera si potrà per passare all'uso (\texttt{\small 28-29}) di -\func{signalfd} per abilitare la notifica sul file descriptor -\var{sigfd}. Questo poi (\texttt{\small 30-33}) dovrà essere aggiunto con -\func{epoll\_ctl} all'elenco di file descriptor controllati con \texttt{epfd}. +file descriptor. Per questo prima li si inseriscono (\texttt{\small 22-25}) in +una maschera di segnali \texttt{sigmask} che useremo con (\texttt{\small 26}) +\func{sigprocmask} per disabilitarli. Con la stessa maschera si potrà per +passare all'uso (\texttt{\small 28-29}) di \func{signalfd} per abilitare la +notifica sul file descriptor \var{sigfd}. Questo poi (\texttt{\small 30-33}) +dovrà essere aggiunto con \func{epoll\_ctl} all'elenco di file descriptor +controllati con \texttt{epfd}. Occorrerà infine (\texttt{\small 35-38}) creare la \textit{named fifo} se questa non esiste ed aprirla per la lettura (\texttt{\small 39-40}); una @@ -3922,13 +3920,12 @@ 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 -\index{memoria~virtuale} 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 \textit{swap}. +Infatti, dato che l'accesso è fatto direttamente attraverso la 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 \textit{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 @@ -4354,33 +4351,30 @@ 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} +virtuale. Questa funzione di sistema è \funcd{mprotect} ed il suo prototipo è: - \funcdecl{int mprotect(const void *addr, size\_t len, int prot)} - - Modifica le protezioni delle pagine di memoria comprese nell'intervallo - specificato. +\begin{funcproto}{ +\fhead{sys/mman.h} +\fdecl{int mprotect(const void *addr, size\_t len, int prot)} +\fdesc{Modifica le protezioni delle pagine di 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} +{La funzione ritorna $0$ in caso di successo e $-1$ per un 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{EACCES}] 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} - + \item[\errcode{ENOMEM}] non è stato possibile allocare le risorse + necessarie all'interno del kernel o si è specificato un indirizzo di + memoria non valido del processo o non corrispondente a pagine mappate + (negli ultimi due casi prima del kernel 2.4.19 veniva prodotto, + erroneamente, \errcode{EFAULT}). + \end{errlist} +} +\end{funcproto} La funzione prende come argomenti un indirizzo di partenza in \param{addr}, allineato alle dimensioni delle pagine di memoria, ed una dimensione @@ -4390,23 +4384,23 @@ protezione verrà applicata a tutte le pagine contenute, anche parzialmente, dall'intervallo fra \param{addr} e \param{addr}+\param{size}-1. Infine Linux supporta alcune operazioni specifiche non disponibili su altri -kernel unix-like. La prima di queste è la possibilità di modificare un -precedente \textit{memory mapping}, ad esempio per espanderlo o restringerlo. -Questo è realizzato dalla funzione \funcd{mremap}, il cui prototipo è: -\begin{functions} - \headdecl{unistd.h} - \headdecl{sys/mman.h} +kernel unix-like per poter usare le quali occorre però dichiarare +\macro{\_GNU\_SOURCE} prima dell'inclusione di \texttt{sys/mman.h}. La prima +di queste è la possibilità di modificare un precedente \textit{memory + mapping}, ad esempio per espanderlo o restringerlo. Questo è realizzato +dalla funzione di sistema \funcd{mremap}, il cui prototipo è: - \funcdecl{void * mremap(void *old\_address, size\_t old\_size , size\_t +\begin{funcproto}{ +\fhead{sys/mman.h} +\fdecl{void * mremap(void *old\_address, size\_t old\_size , size\_t new\_size, unsigned long flags)} - - Restringe o allarga una mappatura in memoria di un file. +\fdesc{Restringe o allarga una mappatura in memoria.} +} - \bodydesc{La funzione restituisce l'indirizzo alla nuova area di memoria in - caso di successo od il valore \const{MAP\_FAILED} (pari a \texttt{(void *) - -1}) in caso di errore, nel qual caso \var{errno} assumerà uno dei - valori: - \begin{errlist} +{La funzione ritorna l'indirizzo alla nuova area di memoria in caso di + successo o il valore \const{MAP\_FAILED} (pari a \texttt{(void *) -1}), nel + qual caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EINVAL}] il valore di \param{old\_address} non è un puntatore valido. \item[\errcode{EFAULT}] ci sono indirizzi non validi nell'intervallo @@ -4417,9 +4411,9 @@ Questo è realizzato dalla funzione \funcd{mremap}, il cui prototipo è: è specificato \const{MREMAP\_MAYMOVE} nei flag. \item[\errcode{EAGAIN}] il segmento di memoria scelto è bloccato e non può essere rimappato. - \end{errlist} - } -\end{functions} + \end{errlist} +} +\end{funcproto} La funzione richiede come argomenti \param{old\_address} (che deve essere allineato alle dimensioni di una pagina di memoria) che specifica il @@ -4427,80 +4421,77 @@ precedente indirizzo del \textit{memory mapping} e \param{old\_size}, che ne indica la dimensione. Con \param{new\_size} si specifica invece la nuova dimensione che si vuole ottenere. Infine l'argomento \param{flags} è una maschera binaria per i flag che controllano il comportamento della funzione. -Il solo valore utilizzato è \const{MREMAP\_MAYMOVE}\footnote{per poter - utilizzare questa costante occorre aver definito \macro{\_GNU\_SOURCE} prima - di includere \headfile{sys/mman.h}.} che consente di eseguire l'espansione -anche quando non è possibile utilizzare il precedente indirizzo. Per questo -motivo, se si è usato questo flag, la funzione può restituire un indirizzo -della nuova zona di memoria che non è detto coincida con \param{old\_address}. - -La funzione si appoggia al sistema della \index{memoria~virtuale} memoria -virtuale per modificare l'associazione fra gli indirizzi virtuali del processo -e le pagine di memoria, modificando i dati direttamente nella -\itindex{page~table} \textit{page table} del processo. Come per -\func{mprotect} la funzione può essere usata in generale, anche per pagine di -memoria non corrispondenti ad un \textit{memory mapping}, e consente così di -implementare la funzione \func{realloc} in maniera molto efficiente. +Il solo valore utilizzato è \const{MREMAP\_MAYMOVE} che consente di eseguire +l'espansione anche quando non è possibile utilizzare il precedente +indirizzo. Per questo motivo, se si è usato questo flag, la funzione può +restituire un indirizzo della nuova zona di memoria che non è detto coincida +con \param{old\_address}. + +La funzione si appoggia al sistema della memoria virtuale per modificare +l'associazione fra gli indirizzi virtuali del processo e le pagine di memoria, +modificando i dati direttamente nella \textit{page table} del processo. Come +per \func{mprotect} la funzione può essere usata in generale, anche per pagine +di memoria non corrispondenti ad un \textit{memory mapping}, e consente così +di implementare la funzione \func{realloc} in maniera molto efficiente. Una caratteristica comune a tutti i sistemi unix-like è che la mappatura in memoria di un file viene eseguita in maniera lineare, cioè parti successive di un file vengono mappate linearmente su indirizzi successivi in memoria. -Esistono però delle applicazioni\footnote{in particolare la tecnica è usata - dai database o dai programmi che realizzano macchine virtuali.} in cui è -utile poter mappare sezioni diverse di un file su diverse zone di memoria. +Esistono però delle applicazioni (in particolare la tecnica è usata dai +database o dai programmi che realizzano macchine virtuali) in cui è utile +poter mappare sezioni diverse di un file su diverse zone di memoria. Questo è ovviamente sempre possibile eseguendo ripetutamente la funzione \func{mmap} per ciascuna delle diverse aree del file che si vogliono mappare -in sequenza non lineare,\footnote{ed in effetti è quello che veniva fatto - anche con Linux prima che fossero introdotte queste estensioni.} ma questo -approccio ha delle conseguenze molto pesanti in termini di prestazioni. -Infatti per ciascuna mappatura in memoria deve essere definita nella -\itindex{page~table} \textit{page table} del processo una nuova area di -memoria virtuale\footnote{quella che nel gergo del kernel viene chiamata VMA - (\textit{virtual memory area}).} che corrisponda alla mappatura, in modo che -questa diventi visibile nello spazio degli indirizzi come illustrato in -fig.~\ref{fig:file_mmap_layout}. - -Quando un processo esegue un gran numero di mappature diverse\footnote{si può - arrivare anche a centinaia di migliaia.} per realizzare a mano una mappatura -non-lineare si avrà un accrescimento eccessivo della sua \itindex{page~table} -\textit{page table}, e lo stesso accadrà per tutti gli altri processi che -utilizzano questa tecnica. In situazioni in cui le applicazioni hanno queste -esigenze si avranno delle prestazioni ridotte, dato che il kernel dovrà -impiegare molte risorse\footnote{sia in termini di memoria interna per i dati - delle \itindex{page~table} \textit{page table}, che di CPU per il loro - aggiornamento.} solo per mantenere i dati di una gran quantità di -\textit{memory mapping}. +in sequenza non lineare (ed in effetti è quello che veniva fatto anche con +Linux prima che fossero introdotte queste estensioni) ma questo approccio ha +delle conseguenze molto pesanti in termini di prestazioni. Infatti per +ciascuna mappatura in memoria deve essere definita nella \textit{page table} +del processo una nuova area di memoria virtuale, quella che nel gergo del +kernel viene chiamata VMA (\textit{virtual memory area}, che corrisponda alla +mappatura, in modo che questa diventi visibile nello spazio degli indirizzi +come illustrato in fig.~\ref{fig:file_mmap_layout}. + +Quando un processo esegue un gran numero di mappature diverse (si può arrivare +anche a centinaia di migliaia) per realizzare a mano una mappatura non-lineare +esso vedrà un accrescimento eccessivo della sua \textit{page table}, e lo +stesso accadrà per tutti gli altri processi che utilizzano questa tecnica. In +situazioni in cui le applicazioni hanno queste esigenze si avranno delle +prestazioni ridotte, dato che il kernel dovrà impiegare molte risorse per +mantenere i dati relativi al \textit{memory mapping}, sia in termini di +memoria interna per i dati delle \textit{page table}, che di CPU per il loro +aggiornamento. Per questo motivo con il kernel 2.5.46 è stato introdotto, ad opera di Ingo Molnar, un meccanismo che consente la mappatura non-lineare. Anche questa è una caratteristica specifica di Linux, non presente in altri sistemi -unix-like. Diventa così possibile utilizzare una sola mappatura -iniziale\footnote{e quindi una sola \textit{virtual memory area} nella - \itindex{page~table} \textit{page table} del processo.} e poi rimappare a -piacere all'interno di questa i dati del file. Ciò è possibile grazie ad una -nuova \textit{system call}, \funcd{remap\_file\_pages}, il cui prototipo è: -\begin{functions} - \headdecl{sys/mman.h} +unix-like. Diventa così possibile utilizzare una sola mappatura iniziale, e +quindi una sola \textit{virtual memory area} nella \textit{page table} del +processo, e poi rimappare a piacere all'interno di questa i dati del file. Ciò +è possibile grazie ad una nuova \textit{system call}, +\funcd{remap\_file\_pages}, il cui prototipo è: - \funcdecl{int remap\_file\_pages(void *start, size\_t size, int prot, +\begin{funcproto}{ +\fhead{sys/mman.h} +\fdecl{int remap\_file\_pages(void *start, size\_t size, int prot, ssize\_t pgoff, int flags)} - - Permette di rimappare non linearmente un precedente \textit{memory mapping}. +\fdesc{Rimappa non linearmente un \textit{memory mapping}.} +} - \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} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EINVAL}] si è usato un valore non valido per uno degli argomenti o \param{start} non fa riferimento ad un \textit{memory mapping} valido creato con \const{MAP\_SHARED}. - \end{errlist} - } -\end{functions} + \end{errlist} + ed inoltre + nel loro significato generico.} +\end{funcproto} Per poter utilizzare questa funzione occorre anzitutto effettuare preliminarmente una chiamata a \func{mmap} con \const{MAP\_SHARED} per -definire l'area di memoria che poi sarà rimappata non linearmente. Poi di +definire l'area di memoria che poi sarà rimappata non linearmente. Poi si chiamerà questa funzione per modificare le corrispondenze fra pagine di memoria e pagine del file; si tenga presente che \func{remap\_file\_pages} permette anche di mappare la stessa pagina di un file in più pagine della @@ -4532,12 +4523,12 @@ 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 \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}. +pagina alla volta con un gran numero di \textit{page fault}, chiaramente se si +sa in anticipo che il file verrà utilizzato 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 @@ -4562,16 +4553,16 @@ disponibile una apposita funzione, \funcd{madvise},\footnote{tratteremo in l'accesso ai file con l'interfaccia classica.} che consente di fornire al kernel delle indicazioni su dette modalità, così che possano essere adottate le opportune strategie di ottimizzazione. Il suo prototipo è: -\begin{functions} - \headdecl{sys/mman.h} - \funcdecl{int madvise(void *start, size\_t length, int advice)} - - Fornisce indicazioni sull'uso previsto di un \textit{memory mapping}. +\begin{funcproto}{ +\fhead{sys/mman.h} +\fdecl{int madvise(void *start, size\_t length, int advice)} +\fdesc{Fornisce indicazioni sull'uso previsto di un \textit{memory mapping}.} +} - \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} +{La funzione ritorna $0$ in caso di successo e $-1$ per un errore, nel qual + caso \var{errno} assumerà uno dei valori: + \begin{errlist} \item[\errcode{EBADF}] la mappatura esiste ma non corrisponde ad un file. \item[\errcode{EINVAL}] \param{start} non è allineato alla dimensione di una pagina, \param{length} ha un valore negativo, o \param{advice} non è @@ -4583,23 +4574,25 @@ le opportune strategie di ottimizzazione. Il suo prototipo è: \item[\errcode{ENOMEM}] gli indirizzi specificati non sono mappati, o, in caso \const{MADV\_WILLNEED}, non c'è sufficiente memoria per soddisfare la richiesta. - \end{errlist} - ed inoltre \errval{EAGAIN} e \errval{ENOSYS}. - } -\end{functions} + \end{errlist} + ed inoltre \errval{EAGAIN} e \errval{ENOSYS} nel loro significato generico.} +\end{funcproto} + La sezione di memoria sulla quale si intendono fornire le indicazioni deve essere indicata con l'indirizzo iniziale \param{start} e l'estensione \param{length}, il valore di \param{start} deve essere allineato, -mentre \param{length} deve essere un numero positivo.\footnote{la versione di - Linux consente anche un valore nullo per \param{length}, inoltre se una - parte dell'intervallo non è mappato in memoria l'indicazione viene comunque - applicata alle restanti parti, anche se la funzione ritorna un errore di - \errval{ENOMEM}.} L'indicazione viene espressa dall'argomento \param{advice} -che deve essere specificato con uno dei valori\footnote{si tenga presente che - gli ultimi tre valori sono specifici di Linux (introdotti a partire dal - kernel 2.6.16) e non previsti dallo standard POSIX.1b.} riportati in -tab.~\ref{tab:madvise_advice_values}. +mentre \param{length} deve essere un numero positivo; la versione di Linux +consente anche un valore nullo per \param{length}, inoltre se una parte +dell'intervallo non è mappato in memoria l'indicazione viene comunque +applicata alle restanti parti, anche se la funzione ritorna un errore di +\errval{ENOMEM}. + +L'indicazione viene espressa dall'argomento \param{advice} che deve essere +specificato con uno dei valori riportati in +tab.~\ref{tab:madvise_advice_values}; si tenga presente che i valori indicati +nella seconda parte sono specifici di Linux e non sono previsti dallo standard +POSIX.1b. \begin{table}[htb] \centering @@ -4609,13 +4602,18 @@ tab.~\ref{tab:madvise_advice_values}. \textbf{Valore} & \textbf{Significato} \\ \hline \hline + \const{MADV\_DONTNEED}& non ci si aspetta nessun accesso nell'immediato + futuro, pertanto le pagine possono essere + liberate dal kernel non appena necessario; l'area + di memoria resterà accessibile, ma un accesso + richiederà che i dati vengano ricaricati dal file + a cui la mappatura fa riferimento.\\ \const{MADV\_NORMAL} & nessuna indicazione specifica, questo è il valore di default usato quando non si è chiamato \func{madvise}.\\ \const{MADV\_RANDOM} & ci si aspetta un accesso casuale all'area indicata, pertanto l'applicazione di una lettura - anticipata con il meccanismo del - \itindex{read-ahead} \textit{read-ahead} (vedi + anticipata con il meccanismo del \textit{read-ahead} (vedi sez.~\ref{sec:file_fadvise}) è di scarsa utilità e verrà disabilitata.\\ \const{MADV\_SEQUENTIAL}& ci si aspetta un accesso sequenziale al file, @@ -4626,39 +4624,35 @@ tab.~\ref{tab:madvise_advice_values}. \const{MADV\_WILLNEED}& ci si aspetta un accesso nell'immediato futuro, pertanto l'applicazione del \textit{read-ahead} deve essere incentivata.\\ - \const{MADV\_DONTNEED}& non ci si aspetta nessun accesso nell'immediato - futuro, pertanto le pagine possono essere - liberate dal kernel non appena necessario; l'area - di memoria resterà accessibile, ma un accesso - richiederà che i dati vengano ricaricati dal file - a cui la mappatura fa riferimento.\\ \hline \const{MADV\_REMOVE} & libera un intervallo di pagine di memoria ed il relativo supporto sottostante; è supportato soltanto sui filesystem in RAM \textit{tmpfs} e - \textit{shmfs}.\footnotemark\\ + \textit{shmfs} se usato su altri tipi di + filesystem causa un errore di \errcode{ENOSYS} + (dal kernel 2.6.16).\\ \const{MADV\_DONTFORK}& impedisce che l'intervallo specificato venga ereditato dal processo figlio dopo una \func{fork}; questo consente di evitare che il - meccanismo del \itindex{copy~on~write} - \textit{copy on write} effettui la rilocazione - delle pagine quando il padre scrive sull'area - di memoria dopo la \func{fork}, cosa che può + meccanismo del \textit{copy on write} effettui la + rilocazione delle pagine quando il padre scrive + sull'area di memoria dopo la \func{fork}, cosa che può causare problemi per l'hardware che esegue - operazioni in DMA su quelle pagine.\\ + operazioni in DMA su quelle pagine (dal kernel + 2.6.16).\\ \const{MADV\_DOFORK} & rimuove l'effetto della precedente - \const{MADV\_DONTFORK}.\\ + \const{MADV\_DONTFORK} (dal kernel 2.6.16).\\ \const{MADV\_MERGEABLE}& marca la pagina come accorpabile (indicazione principalmente ad uso dei sistemi di virtualizzazione).\footnotemark\\ - \hline + \const{MADV\_UNMERGEABLE}& \\ + \hline \end{tabular} \caption{Valori dell'argomento \param{advice} di \func{madvise}.} \label{tab:madvise_advice_values} \end{table} -\footnotetext{se usato su altri tipi di filesystem causa un errore di - \errcode{ENOSYS}.} +\footnotetext{.} \footnotetext{a partire dal kernel 2.6.32 è stato introdotto un meccanismo che identifica pagine di memoria identiche e le accorpa in una unica pagina @@ -5740,11 +5734,11 @@ livello di kernel. % LocalWords: sigwaitinfo FifoReporter Windows ptr sigqueue named timerfd TFD % LocalWords: clockid CLOCK MONOTONIC REALTIME itimerspec interval Resource % LocalWords: ABSTIME gettime temporarily unavailable SIGINT SIGQUIT SIGTERM +% LocalWords: sigfd fifofd break siginf names starting echo Message from Got +% LocalWords: message kill received means exit %%% Local Variables: %%% mode: latex %%% TeX-master: "gapil" %%% End: -% LocalWords: sigfd fifofd break siginf names starting echo Message from Got -% LocalWords: message kill received means exit diff --git a/filedir.tex b/filedir.tex index df4576e..43518ed 100644 --- a/filedir.tex +++ b/filedir.tex @@ -1395,7 +1395,7 @@ diventerebbe piuttosto complicata.\footnote{in genere per questo tipo di non si potrebbe più rimuoverla.} Data la pericolosità di questa operazione e la disponibilità dei collegamenti -simbolici (che vedremo a breve) e dei \itindex{bind~mount} \textit{bind mount} +simbolici (che vedremo a breve) e dei \textit{bind mount} (già visti in sez.~\ref{sec:filesystem_mounting}) che possono fornire la stessa funzionalità senza questi problemi, nel caso di Linux questa capacità è stata completamente disabilitata, e al tentativo di creare un collegamento @@ -3831,12 +3831,12 @@ in \param{pathname}.\footnote{su Linux solo \func{utimensat} è una Torneremo su questa sintassi e sulla sua motivazione in sez.~\ref{sec:file_openat}, quando tratteremo tutte le altre funzioni (le -cosiddette \itindex{at-functions} \textit{at-functions}) che la utilizzano; -essa prevede comunque anche la presenza dell'argomento \param{flags} con cui -attivare flag di controllo che modificano il comportamento della funzione, nel -caso specifico l'unico valore consentito è \const{AT\_SYMLINK\_NOFOLLOW} che -indica alla funzione di non dereferenziare i collegamenti simbolici, cosa che -le permette di riprodurre le funzionalità di \func{lutimes}. +cosiddette \textit{at-functions}) che la utilizzano; essa prevede comunque +anche la presenza dell'argomento \param{flags} con cui attivare flag di +controllo che modificano il comportamento della funzione, nel caso specifico +l'unico valore consentito è \const{AT\_SYMLINK\_NOFOLLOW} che indica alla +funzione di non dereferenziare i collegamenti simbolici, cosa che le permette +di riprodurre le funzionalità di \func{lutimes}. @@ -4324,8 +4324,8 @@ questo controllo prima di aprire il file espone al rischio di una \itindex{race~condition} \textit{race condition} che apre ad un possibile \itindex{symlink~attack} \textit{symlink attack} fra il controllo e l'apertura del file. In questo caso è sempre opportuno usare invece la funzione -\func{faccessat} che tratteremo insieme alle altre \itindex{at-functions} -\textit{at-functions} in sez.~\ref{sec:file_openat}. +\func{faccessat} che tratteremo insieme alle altre \textit{at-functions} in +sez.~\ref{sec:file_openat}. Del tutto analoghe a \func{access} sono le due funzioni \funcm{euidaccess} e \funcm{eaccess} che ripetono lo stesso controllo usando però gli diff --git a/fileio.tex b/fileio.tex index f23053d..eb448e3 100644 --- a/fileio.tex +++ b/fileio.tex @@ -3499,9 +3499,9 @@ Le prime due servono per scrivere su file (lo \itindex{standard~output} su una stringa, in genere l'uso di \func{sprintf} è sconsigliato in quanto è possibile, se non si ha la sicurezza assoluta sulle dimensioni del risultato della stampa, eccedere le dimensioni di \param{str}, con conseguente -sovrascrittura di altre variabili e possibili \itindex{buffer~overflow} -\textit{buffer overflow}. Per questo motivo si consiglia l'uso -dell'alternativa \funcd{snprintf}, il cui prototipo è: +sovrascrittura di altre variabili e possibili \textit{buffer overflow}. Per +questo motivo si consiglia l'uso dell'alternativa \funcd{snprintf}, il cui +prototipo è: \begin{funcproto}{ \fhead{stdio.h} @@ -3699,8 +3699,7 @@ scritti sulla stringa di destinazione: \func{vsprintf}.} \end{funcproto} -\noindent in modo da evitare possibili \itindex{buffer~overflow} buffer -overflow. +\noindent in modo da evitare possibili \textit{buffer overflow}. Per eliminare alla radice questi problemi, la \acr{glibc} supporta una diff --git a/gapil.tex b/gapil.tex index cbfba29..f15cf7b 100644 --- a/gapil.tex +++ b/gapil.tex @@ -132,10 +132,9 @@ hyperfootnotes=false]{hyperref} copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with the Invariant Sections being ``Un preambolo'' - in ``Prefazione'', - with no Front-Cover Texts, and with no Back-Cover Texts. A copy of the - license is included in the section entitled ``GNU Free Documentation - License''. + in ``Prefazione'', with no Front-Cover Texts, and with no Back-Cover Texts. + A copy of the license is included in the section entitled ``GNU Free + Documentation License''. \end{quote} \clearemptydoublepage diff --git a/process.tex b/process.tex index 4b18c30..6a37bb0 100644 --- a/process.tex +++ b/process.tex @@ -697,12 +697,14 @@ cui si trovano in memoria, eliminando quelle che non servono. Questo meccanismo è detto \textsl{paginazione} (o \textit{paging}), ed è uno dei compiti principali del kernel. +\itindbeg{page~fault} + 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 - 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. +reale, avviene quello che viene chiamato un \textit{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 @@ -712,6 +714,8 @@ se la pagina è direttamente disponibile, a tempi estremamente più lunghi, dovuti all'intervento del kernel, qualora sia necessario reperire pagine riposte nella \textit{swap}. +\itindend{page~fault} + Normalmente questo è il prezzo da pagare per avere un multitasking reale, ed in genere il sistema è molto efficiente in questo lavoro; quando però ci siano esigenze specifiche di prestazioni è possibile usare delle funzioni che @@ -731,8 +735,8 @@ commette quando si è manipolato male un puntatore e genera quella che viene chiamata una \itindex{segment~violation} \textit{segment violation}. Se si tenta cioè di leggere o scrivere con un indirizzo per il quale non esiste un'associazione nella memoria virtuale, il kernel risponde al relativo -\itindex{page~fault} \textit{page fault} mandando un segnale \signal{SIGSEGV} -al processo, che normalmente ne causa la terminazione immediata. +\textit{page fault} mandando un segnale \signal{SIGSEGV} al processo, che +normalmente ne causa la terminazione immediata. È pertanto importante capire come viene strutturata la memoria virtuale di un processo. Essa viene divisa in \textsl{segmenti}, cioè un insieme contiguo di @@ -1016,11 +1020,11 @@ sez.~\ref{sec:proc_environ}), in particolare diventa possibile tracciare questo tipo di errori usando la variabile di ambiente \envvar{MALLOC\_CHECK\_} che quando viene definita mette in uso una versione meno efficiente delle funzioni suddette, che però è più tollerante nei confronti di piccoli errori -come quello dei \itindex{double~free} \textit{double~free} o i -\itindex{buffer~overrun} \textit{buffer overrun} di un byte.\footnote{uno - degli errori più comuni, causato ad esempio dalla scrittura di una stringa - di dimensione pari a quella del buffer, in cui ci si dimentica dello zero di - terminazione finale.} In particolare: +come quello dei \itindex{double~free} \textit{double~free} o i \textit{buffer + overrun} di un byte.\footnote{uno degli errori più comuni, causato ad + esempio dalla scrittura di una stringa di dimensione pari a quella del + buffer, in cui ci si dimentica dello zero di terminazione finale.} In +particolare: \begin{itemize*} \item se la variabile è posta a $0$ gli errori vengono ignorati; \item se la variabile è posta a $1$ viene stampato un avviso sullo @@ -1454,15 +1458,15 @@ selezionare con maggior finezza le pagine da bloccare, ad esempio usando \const{MCL\_FUTURE} ci si può limitare a tutte le pagine allocate a partire dalla chiamata della funzione. -In ogni caso un processo real-time che deve entrare in una +In ogni caso un processo \textit{real-time} che deve entrare in una \index{sezione~critica} sezione critica deve provvedere a riservare memoria sufficiente prima dell'ingresso, per scongiurare l'occorrenza di un eventuale -\itindex{page~fault} \textit{page fault} causato dal meccanismo di -\itindex{copy~on~write} \textit{copy on write}. Infatti se nella -\index{sezione~critica} 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. +\textit{page fault} causato dal meccanismo di \itindex{copy~on~write} +\textit{copy on write}. Infatti se nella \index{sezione~critica} sezione +critica si va ad utilizzare memoria che non è ancora stata riportata in RAM si +potrebbe avere un \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 \index{variabili!automatiche} @@ -1570,8 +1574,7 @@ errori di programmazione. Esempi di questi errori sono i \itindex{double~free} allocazione,\footnote{entrambe queste operazioni causano in genere la corruzione dei dati di controllo delle funzioni di allocazione, che vengono anch'essi mantenuti nello \itindex{heap} \textit{heap} per tenere traccia - delle zone di memoria allocata.} o i classici \itindex{memory~leak} -\textit{memory leak}. + delle zone di memoria allocata.} o i classici \textit{memory leak}. Abbiamo visto in sez.~\ref{sec:proc_mem_lock} come una prima funzionalità di ausilio nella ricerca di questi errori sia l'uso della variabile di ambiente diff --git a/prochand.tex b/prochand.tex index cd67422..3ba60c6 100644 --- a/prochand.tex +++ b/prochand.tex @@ -612,7 +612,7 @@ comune dopo l'esecuzione di una \func{fork} è la seguente: (vedi sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot}); \item la maschera dei permessi di creazione dei file (vedi sez.~\ref{sec:file_perm_management}); -\item la \index{maschera~dei~segnali} maschera dei segnali bloccati (vedi +\item la maschera dei segnali bloccati (vedi sez.~\ref{sec:sig_sigmask}) e le azioni installate (vedi sez.~\ref{sec:sig_gen_beha}); \item i segmenti di memoria condivisa agganciati al processo (vedi @@ -1558,8 +1558,7 @@ seguente: % TODO ===========Importante============= % TODO questo sotto è incerto, verificare % TODO ===========Importante============= -\item la \index{maschera~dei~segnali} maschera dei segnali (si veda - sez.~\ref{sec:sig_sigmask}). +\item la maschera dei segnali (si veda sez.~\ref{sec:sig_sigmask}). \end{itemize*} Una serie di proprietà del processo originale, che non avrebbe senso mantenere