X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=819401334288d84c8dc598d2fcdc5468a244667b;hp=a18a0b1dae1aab1eb895726e4a70be1f16444c4d;hb=33a54e1bfa5e62cb90d84c2d5f2d0c53864f6bec;hpb=08dda6d422df113ce687fa8a4305feb55bbf98d0 diff --git a/process.tex b/process.tex index a18a0b1..8194013 100644 --- a/process.tex +++ b/process.tex @@ -1,6 +1,6 @@ %% process.tex %% -%% Copyright (C) 2000-2007 Simone Piccardi. Permission is granted to +%% Copyright (C) 2000-2011 Simone Piccardi. Permission is granted to %% copy, distribute and/or modify this document under the terms of the GNU Free %% Documentation License, Version 1.1 or any later version published by the %% Free Software Foundation; with the Invariant Sections being "Un preambolo", @@ -35,8 +35,8 @@ ciascun processo vedr tutte le parti uguali siano condivise), avrà un suo spazio di indirizzi, variabili proprie e sarà eseguito in maniera completamente indipendente da tutti gli altri.\footnote{questo non è del tutto vero nel caso di un programma - \textit{multi-thread}, ma la gestione dei \textit{thread} in Linux sarà - trattata a parte.} + \textit{multi-thread}, ma la gestione dei \itindex{thread} \textit{thread} + in Linux sarà trattata a parte in cap.~\ref{cha:threads}.} \subsection{La funzione \func{main}} @@ -49,8 +49,8 @@ dinamico del codice e alla fine lo esegue. Infatti, a meno di non aver specificato il flag \texttt{-static} durante la compilazione, tutti i programmi in Linux sono incompleti e necessitano di essere \textsl{collegati} alle librerie condivise quando vengono avviati. La procedura è controllata da -alcune variabili di ambiente e dal contenuto di \file{/etc/ld.so.conf}. I -dettagli sono riportati nella man page di \cmd{ld.so}. +alcune variabili di ambiente e dal contenuto di \conffile{/etc/ld.so.conf}. I +dettagli sono riportati nella pagina di manuale di \cmd{ld.so}. Il sistema fa partire qualunque programma chiamando la funzione \func{main}; sta al programmatore chiamare così la funzione principale del programma da cui @@ -151,13 +151,14 @@ non vengono salvati e le eventuali funzioni registrate con \func{atexit} e \bodydesc{La funzione non ritorna. Il processo viene terminato.} \end{prototype} -La funzione chiude tutti i file descriptor appartenenti al processo (si tenga +La funzione chiude tutti i file descriptor appartenenti al processo; si tenga presente che questo non comporta il salvataggio dei dati bufferizzati degli -stream), fa sì che ogni figlio del processo sia adottato da \cmd{init} (vedi -cap.~\ref{cha:process_handling}), manda un segnale \const{SIGCHLD} al processo -padre (vedi sez.~\ref{sec:sig_job_control}) ed infine ritorna lo stato di -uscita specificato in \param{status} che può essere raccolto usando la -funzione \func{wait} (vedi sez.~\ref{sec:proc_wait}). +stream, (torneremo sulle due interfacce dei file a partire da +cap.~\ref{cha:file_intro}), fa sì che ogni figlio del processo sia adottato da +\cmd{init} (vedi cap.~\ref{cha:process_handling}), manda un segnale +\const{SIGCHLD} al processo padre (vedi sez.~\ref{sec:sig_job_control}) ed +infine ritorna lo stato di uscita specificato in \param{status} che può essere +raccolto usando la funzione \func{wait} (vedi sez.~\ref{sec:proc_wait}). \subsection{Le funzioni \func{atexit} e \func{on\_exit}} @@ -182,7 +183,7 @@ che si pu Registra la funzione \param{function} per la chiamata all'uscita dal programma. - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + \bodydesc{La funzione restituisce $0$ in caso di successo e $-1$ in caso di fallimento, \var{errno} non viene modificata.} \end{prototype} \noindent la funzione richiede come argomento l'indirizzo di una opportuna @@ -198,7 +199,7 @@ definita su altri sistemi; il suo prototipo Registra la funzione \param{function} per la chiamata all'uscita dal programma. - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di fallimento, \var{errno} non viene modificata.} \end{prototype} @@ -234,7 +235,44 @@ normalmente un programma \begin{figure}[htb] \centering - \includegraphics[width=9cm]{img/proc_beginend} +% \includegraphics[width=9cm]{img/proc_beginend} + \begin{tikzpicture}[>=stealth] + \filldraw[fill=black!35] (-0.3,0) rectangle (12,1); + \draw(5.5,0.5) node {\large{kernel}}; + + \filldraw[fill=black!15] (1.5,2) rectangle (4,3); + \draw (2.75,2.5) node {\texttt{ld-linux.so}}; + \draw [->] (2.75,1) -- (2.75,2); + \draw (2.75,1.5) node [anchor=west]{\texttt{exec}}; + + \filldraw[fill=black!15,rounded corners] (1.5,4) rectangle (4,5); + \draw (2.75,4.5) node {\texttt{main}}; + + \draw [<->, dashed] (2.75,3) -- (2.75,4); + \draw [->] (1.5,4.5) -- (0.3,4.5) -- (0.3,1); + \draw (0.9,4.5) node [anchor=south] {\texttt{\_exit}}; + + \filldraw[fill=black!15,rounded corners] (1.5,6) rectangle (4,7); + \draw (2.75,6.5) node {\texttt{funzione}}; + + \draw [<->, dashed] (2.75,5) -- (2.75,6); + \draw [->] (1.5,6.5) -- (0.05,6.5) -- (0.05,1); + \draw (0.9,6.5) node [anchor=south] {\texttt{\_exit}}; + + \draw (6.75,4.5) node (exit) [rectangle,fill=black!15,minimum width=2.5cm,minimum height=1cm,rounded corners, draw]{\texttt{exit}}; + + \draw[->] (4,6.5) -- node[anchor=south west]{\texttt{exit}} (exit); + \draw[->] (4,4.5) -- node[anchor=south]{\texttt{exit}} (exit); + \draw[->] (exit) -- node[anchor=east]{\texttt{\_exit}}(6.75,1); + + \draw (10,4.5) node (exithandler1) [rectangle,fill=black!15,rounded corners, draw]{exit handler}; + \draw (10,5.5) node (exithandler2) [rectangle,fill=black!15,rounded corners, draw]{exit handler}; + \draw (10,3.5) node (stream) [rectangle,fill=black!15,rounded corners, draw]{chiusura stream}; + + \draw[<->, dashed] (exithandler1) -- (exit); + \draw[<->, dashed] (exithandler2) -- (exit); + \draw[<->, dashed] (stream) -- (exit); + \end{tikzpicture} \caption{Schema dell'avvio e della conclusione di un programma.} \label{fig:proc_prog_start_stop} \end{figure} @@ -336,12 +374,12 @@ Inoltre per certe applicazioni gli algoritmi di gestione della memoria Benché lo spazio di indirizzi virtuali copra un intervallo molto ampio, solo una parte di essi è effettivamente allocato ed utilizzabile dal processo; il tentativo di accedere ad un indirizzo non allocato è un tipico errore che si -commette quando si è manipolato male un puntatore e genera quello che viene -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 \itindex{page~fault} \textit{page - fault} mandando un segnale \const{SIGSEGV} al processo, che normalmente ne -causa la terminazione immediata. +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 da un indirizzo per il quale non esiste +un'associazione della pagina virtuale, il kernel risponde al relativo +\itindex{page~fault} \textit{page fault} mandando un segnale \const{SIGSEGV} +al processo, che normalmente ne causa la terminazione immediata. È pertanto importante capire come viene strutturata \index{memoria~virtuale} \textsl{la memoria virtuale} di un processo. Essa viene divisa in @@ -406,12 +444,13 @@ seguenti segmenti: automaticamente il codice necessario, seguendo quella che viene chiamata una \textit{calling convention}; quella standard usata con il C ed il C++ è detta \textit{cdecl} e prevede che gli argomenti siano caricati nello - stack fal chiamante da destra a sinistra, e che si il chimante stesso ad - eseguire la ripulitura dello stack al ritorno della funzione, se ne - possono però utilizzare di alternative (ad esempio nel pascal gli - argomenti sono inseriti da sinistra a destra ed è compito del chiamato - ripulire lo stack), in genere non ci si deve preoccupare di questo - fintanto che non si mescolano funzioni scritte con linguaggi diversi.} + \textit{stack} dal chiamante da destra a sinistra, e che si il chiamante + stesso ad eseguire la ripulitura dello \textit{stack} al ritorno della + funzione, se ne possono però utilizzare di alternative (ad esempio nel + pascal gli argomenti sono inseriti da sinistra a destra ed è compito del + chiamato ripulire lo \textit{stack}), in genere non ci si deve preoccupare + di questo fintanto che non si mescolano funzioni scritte con linguaggi + diversi.} La dimensione di questo segmento aumenta seguendo la crescita dello \itindex{stack} \textit{stack} del programma, ma non viene ridotta quando @@ -420,7 +459,27 @@ seguenti segmenti: \begin{figure}[htb] \centering - \includegraphics[height=12cm]{img/memory_layout} +% \includegraphics[height=12cm]{img/memory_layout} + \begin{tikzpicture} + \draw (0,0) rectangle (4,1); + \draw (2,0.5) node {text}; + \draw (0,1) rectangle (4,2.5); + \draw (2,1.75) node {dati inizializzati}; + \draw (0,2.5) rectangle (4,5); + \draw (2,3.75) node {dati non inizializzati}; + \draw (0,5) rectangle (4,9); + \draw[dashed] (0,6) -- (4,6); + \draw[dashed] (0,8) -- (4,8); + \draw (2,5.5) node {heap}; + \draw (2,8.5) node {stack}; + \draw [->] (2,6) -- (2,6.5); + \draw [->] (2,8) -- (2,7.5); + \draw (0,9) rectangle (4,10); + \draw (2,9.5) node {environment}; + \draw (4,0) node [anchor=west] {\texttt{0x08000000}}; + \draw (4,5) node [anchor=west] {\texttt{0x08xxxxxx}}; + \draw (4,9) node [anchor=west] {\texttt{0xC0000000}}; + \end{tikzpicture} \caption{Disposizione tipica dei segmenti di memoria di un processo.} \label{fig:proc_mem_layout} \end{figure} @@ -560,19 +619,19 @@ che, quando l'argomento operazione. Le \acr{glibc} hanno un'implementazione delle funzioni di allocazione che è -controllabile dall'utente attraverso alcune variabili di ambiente, in -particolare diventa possibile tracciare questo tipo di errori usando la -variabile di ambiente \val{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 di chiamate doppie a -\func{free}. In particolare: -\begin{itemize*} +controllabile dall'utente attraverso alcune variabili di ambiente (vedi +sez.~\ref{sec:proc_environ}), in particolare diventa possibile tracciare +questo tipo di errori usando la variabile di ambiente \val{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 di chiamate doppie a \func{free}. In particolare: +\begin{itemize} \item se la variabile è posta a zero gli errori vengono ignorati; \item se è posta ad 1 viene stampato un avviso sullo \textit{standard error} (vedi sez.~\ref{sec:file_std_stream}); \item se è posta a 2 viene chiamata \func{abort}, che in genere causa l'immediata conclusione del programma. -\end{itemize*} +\end{itemize} Il problema più comune e più difficile da risolvere che si incontra con le funzioni di allocazione è quando non viene opportunamente liberata la memoria @@ -587,7 +646,7 @@ causando a lungo andare un esaurimento della memoria disponibile (e la probabile impossibilità di proseguire l'esecuzione del programma). Il problema è che l'esaurimento della memoria può avvenire in qualunque -momento, in corrispondenza ad una qualunque chiamata di \func{malloc}, che può +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 \itindex{memory~leak} \textit{memory leak}. @@ -630,21 +689,21 @@ sostituti opportuni delle funzioni di allocazione in grado, senza neanche ricompilare il programma,\footnote{esempi sono \textit{Dmalloc} \href{http://dmalloc.com/}{\textsf{http://dmalloc.com/}} di Gray Watson ed \textit{Electric Fence} di Bruce Perens.} di eseguire diagnostiche anche -molto complesse riguardo l'allocazione della memoria. - - -Una possibile alternativa all'uso di \func{malloc}, che non soffre dei -problemi di \itindex{memory~leak} \textit{memory leak} descritti in -precedenza, è la funzione \funcd{alloca}, che invece di allocare la memoria -nello \itindex{heap} \textit{heap} usa il segmento di \itindex{stack} -\textit{stack} della funzione corrente. La sintassi è identica a quella di -\func{malloc}, il suo prototipo è: +molto complesse riguardo l'allocazione della memoria. Vedremo alcune delle +funzionalità di ausilio presenti nelle \acr{glibc} in +sez.~\ref{sec:proc_memory_adv_management}. + +Una possibile alternativa all'uso di \func{malloc}, per evitare di soffrire +dei problemi di \itindex{memory~leak} \textit{memory leak} descritti in +precedenza, è di allocare la memoria nel segmento di \itindex{stack} +\textit{stack} della funzione corrente invece che nello \itindex{heap} +\textit{heap}, per farlo si può usare la funzione \funcd{alloca}, la cui +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. + Alloca \param{size} byte nello \textit{stack}. - \bodydesc{La funzione restituisce il puntatore alla zona di memoria allocata - in caso di successo e \val{NULL} in caso di fallimento, nel qual caso - \var{errno} assumerà il valore \errval{ENOMEM}.} + \bodydesc{La funzione restituisce il puntatore alla zona di memoria + allocata.} \end{prototype} La funzione alloca la quantità di memoria (non inizializzata) richiesta @@ -672,16 +731,6 @@ suo utilizzo quindi limita la portabilit non può essere usata nella lista degli argomenti di una funzione, perché lo spazio verrebbe allocato nel mezzo degli stessi. -% Questo è riportato solo dal manuale delle glibc, nelle pagine di manuale non c'è -% traccia di tutto ciò -% -%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. -% TODO inserire più informazioni su alloca come da man page - - Inoltre non è chiaramente possibile usare \func{alloca} per allocare memoria che deve poi essere usata anche al di fuori della funzione in cui essa viene chiamata, dato che all'uscita dalla funzione lo spazio allocato diventerebbe @@ -689,30 +738,52 @@ libero, e potrebbe essere sovrascritto all'invocazione di nuove funzioni. Questo è lo stesso problema che si può avere con le variabili automatiche, su cui torneremo in sez.~\ref{sec:proc_auto_var}. +Infine non esiste un modo di sapere se l'allocazione ha avuto successo, la +funzione infatti viene realizzata inserendo del codice \textit{inline} nel +programma\footnote{questo comporta anche il fatto che non è possibile + sostituirla con una propria versione o modificarne il comportamento + collegando il proprio programma con un'altra libreria.} che si limita a +modificare il puntatore nello \itindex{stack} \textit{stack} e non c'è modo di +sapere se se ne sono superate le dimensioni, per cui in caso di fallimento +nell'allocazione il comportamento del programma può risultare indefinito, +dando luogo ad una \itindex{segment~violation} \textit{segment violation} la +prima volta che cercherà di accedere alla memoria non effettivamente +disponibile. Le due funzioni seguenti\footnote{le due funzioni sono state definite con BSD - 4.3, non fanno parte delle librerie standard del C e mentre sono state - esplicitamente escluse dallo standard POSIX.} vengono utilizzate soltanto -quando è necessario effettuare direttamente la gestione della memoria -associata allo spazio dati di un processo, ad esempio qualora si debba -implementare la propria versione delle funzioni di allocazione della memoria. -La prima funzione è \funcd{brk}, ed il suo prototipo è: + 4.3, sono marcate obsolete in SUSv2 e non fanno parte delle librerie + standard del C e mentre sono state esplicitamente rimosse dallo standard + POSIX/1-2001.} vengono utilizzate soltanto quando è necessario effettuare +direttamente la gestione della memoria associata allo spazio dati di un +processo, ad esempio qualora si debba implementare la propria versione delle +funzioni di allocazione della memoria. Per poterle utilizzare è necessario +definire una della macro di funzionalità (vedi +sez.~\ref{sec:intro_gcc_glibc_std}) fra \macro{\_BSD\_SOURCE}, +\macro{\_SVID\_SOURCE} e \macro{\_XOPEN\_SOURCE} (ad un valore maggiore o +ugiale di 500). La prima funzione è \funcd{brk}, ed il suo prototipo è: \begin{prototype}{unistd.h}{int brk(void *end\_data\_segment)} Sposta la fine del segmento dei dati. - \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di + \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di fallimento, nel qual caso \var{errno} assumerà il valore \errval{ENOMEM}.} \end{prototype} -La funzione è un'interfaccia diretta all'omonima system call ed imposta -l'indirizzo finale del \index{segmento!dati} segmento dati di un processo -all'indirizzo specificato da \param{end\_data\_segment}. Quest'ultimo deve -essere un valore ragionevole, ed inoltre la dimensione totale del segmento non -deve comunque eccedere un eventuale limite (si veda -sez.~\ref{sec:sys_resource_limit}) imposto sulle dimensioni massime dello -spazio dati del processo. - -Una seconda funzione per la manipolazione delle dimensioni +La funzione è un'interfaccia all'omonima system call ed imposta l'indirizzo +finale del \index{segmento!dati} segmento dati di un processo all'indirizzo +specificato da \param{end\_data\_segment}. Quest'ultimo deve essere un valore +ragionevole, ed inoltre la dimensione totale del segmento non deve comunque +eccedere un eventuale limite (si veda sez.~\ref{sec:sys_resource_limit}) +imposto sulle dimensioni massime dello spazio dati del processo. + +Il valore di ritorno della funzione fa riferimento alla versione fornita dalle +\acr{glibc}, in realtà in Linux la \textit{system call} corrispondente +restituisce come valore di ritorno il nuovo valore della fine del +\index{segmento!dati} segmento dati in caso di successo e quello corrente in +caso di fallimento, è la funzione di interfaccia usata dalle \acr{glibc} che +fornisce i valori di ritorno appena descritti, questo può non accadere se si +usano librerie diverse. + +Una seconda funzione per la manipolazione diretta delle dimensioni \index{segmento!dati} del segmento dati\footnote{in questo caso si tratta soltanto di una funzione di libreria, e non di una system call.} è \funcd{sbrk}, ed il suo prototipo è: @@ -774,6 +845,67 @@ motivi per cui si possono avere di queste necessit crittografia richiedono il blocco di alcune pagine di memoria. \end{itemize} +Per ottenere informazioni sulle modalità in cui un programma sta usando la +memoria virtuale è disponibile una apposita funzione, \funcd{mincore}, che +però non è standardizzata da POSIX e pertanto non è disponibile su tutte le +versioni di kernel unix-like;\footnote{nel caso di Linux devono essere + comunque definite le macro \macro{\_BSD\_SOURCE} e \macro{\_SVID\_SOURCE}.} +il suo prototipo è: +\begin{functions} + \headdecl{unistd.h} + \headdecl{sys/mman.h} + + \funcdecl{int mincore(void *addr, size\_t length, unsigned char *vec)} + Ritorna lo stato delle pagine di memoria occupate da un processo. + + \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di + errore, nel qual caso \var{errno} assumerà uno dei valori seguenti: + \begin{errlist} + \item[\errcode{ENOMEM}] o \param{addr} + \param{length} eccede la dimensione + della memoria usata dal processo o l'intervallo di indirizzi specificato + non è mappato. + \item[\errcode{EINVAL}] \param{addr} non è un multiplo delle dimensioni di + una pagina. + \item[\errcode{EFAULT}] \param{vec} punta ad un indirizzo non valido. + \item[\errcode{EAGAIN}] il kernel è temporaneamente non in grado di fornire + una risposta. + \end{errlist} +} +\end{functions} + +La funzione permette di ottenere le informazioni sullo stato della mappatura +della memoria per il processo chiamante, specificando l'intervallo da +esaminare con l'indirizzo iniziale (indicato con l'argomento \param{addr}) e +la lunghezza (indicata con l'argomento \param{length}). L'indirizzo iniziale +deve essere un multiplo delle dimensioni di una pagina, mentre la lunghezza +può essere qualunque, fintanto che si resta nello spazio di indirizzi del +processo,\footnote{in caso contrario si avrà un errore di \errcode{ENOMEM}; + fino al kernel 2.6.11 in questo caso veniva invece restituito + \errcode{EINVAL}, in considerazione che il caso più comune in cui si + verifica questo errore è quando si usa per sbaglio un valore negativo + di \param{length}, che nel caso verrebbe interpretato come un intero + positivo di grandi dimensioni.} ma il risultato verrà comunque fornito per +l'intervallo compreso fino al multiplo successivo. + +I risultati della funzione vengono forniti nel vettore puntato da \param{vec}, +che deve essere allocato preventivamente e deve essere di dimensione +sufficiente a contenere tanti byte quante sono le pagine contenute +nell'intervallo di indirizzi specificato.\footnote{la dimensione cioè deve + essere almeno pari a \code{(length+PAGE\_SIZE-1)/PAGE\_SIZE}. } Al ritorno +della funzione il bit meno significativo di ciascun byte del vettore sarà +acceso se la pagina di memoria corrispondente è al momento residente in +memoria, o cancellato altrimenti. Il comportamento sugli altri bit è +indefinito, essendo questi al momento riservati per usi futuri. Per questo +motivo in genere è comunque opportuno inizializzare a zero il contenuto del +vettore, così che le pagine attualmente residenti in memoria saranno indicata +da un valore non nullo del byte corrispondente. + +Dato che lo stato della memoria di un processo può cambiare continuamente, il +risultato di \func{mincore} è assolutamente provvisorio e lo stato delle +pagine potrebbe essere già cambiato al ritorno stesso della funzione, a meno +che, come vedremo ora, non si sia attivato il meccanismo che forza il +mantenimento di una pagina sulla memoria. + \itindbeg{memory~locking} Il meccanismo che previene la \index{paginazione} paginazione di parte della @@ -814,7 +946,6 @@ standard POSIX.1 richiede che sia definita in \file{unistd.h} la macro in byte.\footnote{con Linux questo non avviene e si deve ricorrere alla funzione \func{getpagesize}, vedi sez.~\ref{sec:sys_memory_res}.} - A partire dal 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 @@ -838,7 +969,7 @@ prototipi sono: \funcdecl{int munlock(const void *addr, size\_t len)} Rimuove il blocco della paginazione su un intervallo di memoria. - \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 in + \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ in caso di errore, nel qual caso \var{errno} assumerà uno dei valori seguenti: \begin{errlist} @@ -916,61 +1047,269 @@ ci si scrive sopra. \itindend{memory~locking} -% TODO documentare \func{madvise} -% TODO documentare \func{mincore} +\index{memoria~virtuale|)} -\index{memoria~virtuale|)} +\subsection{Gestione avanzata dell'allocazione della memoria} +\label{sec:proc_memory_adv_management} + +La trattazione delle funzioni di allocazione di sez.~\ref{sec:proc_mem_alloc} +si è limitata a coprire le esigenze generiche di un programma, in cui non si +hanno dei requisiti specifici e si lascia il controllo delle modalità di +allocazione alle funzioni di libreria. Tuttavia esistono una serie di casi in +cui può essere necessario avere un controllo più dettagliato delle modalità +con cui la memoria viene allocata; nel qual caso potranno venire in aiuto le +funzioni trattate in questa sezione. + +Le prime funzioni che tratteremo sono quelle che consentono di richiedere di +allocare un blocco di memoria ``\textsl{allineato}'' ad un multiplo una certa +dimensione. Questo tipo di esigenza emerge usualmente quando si devono +allocare dei buffer da utilizzare per eseguire dell'I/O diretto su dispositivi +a blocchi. In questo caso infatti il trasferimento di dati viene eseguito per +blocchi di dimensione fissa, ed è richiesto che l'indirizzo di partenza del +buffer sia un multiplo intero di questa dimensione, usualmente 512 byte. In +tal caso l'uso di \func{malloc} non è sufficiente, ed occorre utilizzare una +funzione specifica. + +Tradizionalmente per rispondere a questa esigenza sono state crate due +funzioni diverse, \funcd{memalign} e \funcd{valloc}, oggi obsolete; i +rispettivi prototipi sono: +\begin{functions} + \headdecl{malloc.h} + \funcdecl{void *valloc(size\_t size)} Alloca un blocco di memoria allineato + alla dimensione di una pagina di memoria. -% \subsection{Gestione avanzata dell'allocazione della memoria} -% \label{sec:proc_mem_malloc_custom} -% TODO: trattare le funzionalità avanzate di \func{malloc} + \funcdecl{void *memalign(size\_t boundary, size\_t size)} + Alloca un blocco di memoria allineato ad un multiplo di \param{boundary}. + + \bodydesc{Entrambe le funzioni ritornano un puntatore al blocco di memoria + allocato in caso di successo e \val{NULL} in caso di errore, nel qual + caso \var{errno} assumerà uno dei valori seguenti: + \begin{errlist} + \item[\errcode{ENOMEM}] non c'è memoria sufficiente per l'allocazione. + \item[\errcode{EINVAL}] \param{boundary} non è multiplo di due. + \end{errlist} +} +\end{functions} +Le funzioni restituiscono il puntatore al buffer di memoria allocata, che per +\func{memalign} sarà un multiplo di \param{boundary} mentre per \func{valloc} +un multiplo della dimensione di una pagina di memoria. Nel caso della versione +fornita dalle \acr{glibc} la memoria allocata con queste funzioni deve essere +liberata con \func{free}, cosa che non è detto accada con altre +implementazioni. + +Nessuna delle due funzioni ha una chiara standardizzazione (nessuna delle due +compare in POSIX.1), ed inoltre ci sono indicazioni discordi sui file che ne +contengono la definizione;\footnote{secondo SUSv2 \func{valloc} è definita in + \texttt{stdlib.h}, mentre sia le \acr{glibc} che le precedenti \acr{libc4} e + \acr{lic5} la dichiarano in \texttt{malloc.h}, lo stesso vale per + \func{memalign} che in alcuni sistemi è dichiarata in \texttt{stdlib.h}.} +per questo motivo il loro uso è sconsigliato, essendo state sostituite dalla +nuova \funcd{posix\_memalign}, che è stata standardizzata in POSIX.1d; il suo +prototipo è: +\begin{prototype}{stdlib.h}{posix\_memalign(void **memptr, size\_t alignment, + size\_t size) } + Alloca un buffer di memoria allineato ad un multiplo di \param{alignment}. + + \bodydesc{La funzione restituisce 0 in caso di successo e \val{NULL} in caso + di fallimento, o uno dei due codici di errore \errcode{ENOMEM} o + \errcode{EINVAL}; \var{errno} non viene impostata.} +\end{prototype} +La funzione restituisce il puntatore al buffer allocato all'indirizzo indicato +da \param{memptr}. La funzione fallisce nelle stesse condizioni delle due +funzioni precedenti, ma a differenza di \func{memalign} restituisce un codice +di errore \errcode{EINVAL} anche se \param{alignment} non è un multiplo della +la dimensione di \code{sizeof(void *)}. Come per le precedenti la memoria +allocata con \func{posix\_memalign} può essere disallocata con +\func{free}.\footnote{che in questo caso è quanto richiesto dallo standard.} + +Un secondo caso in cui risulta estremamente utile poter avere un maggior +controllo delle modalità di allocazione della memoria è quello in cui cercano +errori di programmazione. Esempi di questi errori sono chiamate doppie alla +funzione \func{free} con lo stesso puntatore, o i cosiddetti +\itindex{buffer~overrun} \textit{buffer overrun}, cioè le scritture su un buffer +oltre le dimensioni della sua 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}. + +Una prima funzionalità di ausilio nella ricerca di questi errori viene fornita +dalla \acr{glibc} tramite l'uso della variabile di ambiente +\var{MALLOC\_CHECK\_}. Quando questa viene definita al posto della versione +ordinaria delle funzioni di allocazione (\func{malloc}, \func{calloc}, +\func{realloc}, e \func{free}) viene usata una versione meno efficiente ma in +grado di rilevare (e tollerare) alcuni degli errori più semplici, come le +doppie chiamate a \func{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 questo caso a seconda del valore assegnato a \var{MALLOC\_CHECK\_} si +avranno diversi comportamenti: con 0 l'errore sarà ignorato, con 1 verrà +stampato un messaggio sullo \textit{standard error} (vedi +sez.~\ref{sec:file_std_stream}), con 2 verrà invocata la funzione \func{abort} +(vedi sez.~\ref{sec:sig_alarm_abort}) che termina il programma, con 3 viene +sia stampato il messaggio d'errore che abortito il programma. In genere è +opportuno definire la variabile ad un valore diverso da zero che consente di +rilevare un errore nel momento in cui avviene. + +Una modalità alternativa per effettuare dei controlli di consistenza sullo +stato delle allocazioni di memoria eseguite con \func{malloc}, anche questa +fornita come estensione specifica (e non standard) delle \acr{glibc}, è quella +di utilizzare la funzione \funcd{mcheck}, che deve essere chiamata prima di +eseguire qualunque allocazione con \func{malloc}; il suo prototipo è: +\begin{prototype}{mcheck.h}{mcheck(void (*abortfn) (enum mcheck\_status + status))} + Attiva i controlli di consistenza delle allocazioni eseguite da \func{malloc}. + + \bodydesc{La funzione restituisce 0 in caso di successo e $-1$ in caso di + fallimento; \var{errno} non viene impostata.} +\end{prototype} -\section{Argomenti, opzioni ed ambiente di un processo} -\label{sec:proc_options} +La funzione consente di registrare una funzione di emergenza, da passare come +argomento, che verrà eseguita tutte le volte che, in una successiva esecuzione +di \func{malloc}, venissero trovate delle inconsistenze, come delle operazioni +di scrittura oltre i limiti dei buffer allocati. Per questo motivo la funzione +deve essere chiamata prima di qualunque allocazione di memoria, altrimenti +fallirà con un valore di ritorno pari a $-1$. + +Se come argomento di \func{mcheck} si passa \var{NULL} verrà utilizzata una +funzione predefinita che stampa un messaggio di errore ed invoca la funzione +\func{abort} (vedi sez.~\ref{sec:sig_alarm_abort}), altrimenti si dovrà create +una funzione personalizzata che verrà eseguita ricevendo un unico argomento di +tipo \type{mcheck\_status},\footnote{trattasi in sostanza di un codice di + errore che la funzione di emergenza potrà utilizzare per prendere le + opportune azioni.} un tipo enumerato che può assumere soltanto i valori di +tab.~\ref{tab:mcheck_status_value}. -Tutti i programmi hanno la possibilità di ricevere argomenti e opzioni quando -vengono lanciati. Il passaggio degli argomenti è effettuato attraverso gli -argomenti \param{argc} e \param{argv} della funzione \func{main}, che vengono -passati al programma dalla shell (o dal processo che esegue la \func{exec}, -secondo le modalità che vedremo in sez.~\ref{sec:proc_exec}) quando questo -viene messo in esecuzione. +\begin{table}[htb] + \centering + \footnotesize + \begin{tabular}[c]{|l|p{7cm}|} + \hline + \textbf{Valore} & \textbf{Significato} \\ + \hline + \hline + \macro{MCHECK\_OK} & riportato (a \func{mprobe}) se nessuna + inconsistenza è presente.\\ + \macro{MCHECK\_DISABLED}& riportato (a \func{mprobe}) se si è chiamata + \func{mcheck} dopo aver già usato + \func{malloc}.\\ + \macro{MCHECK\_HEAD} & i dati immediatamente precedenti il buffer sono + stati modificati, avviene in genere quando si + decrementa eccessivamente il valore di un + puntatore scrivendo poi prima dell'inizio del + buffer.\\ + \macro{MCHECK\_TAIL} & i dati immediatamente seguenti il buffer sono + stati modificati, succede quando si va scrivere + oltre la dimensione correttta del buffer.\\ + \macro{MCHECK\_FREE} & il buffer è già stato disallocato.\\ + \hline + \end{tabular} + \caption{Valori dello stato dell'allocazione di memoria ottenibili dalla + funzione di teminazione installata con \func{mcheck}.} + \label{tab:mcheck_status_value} +\end{table} + +Una volta che si sia chiamata \func{mcheck} con successo si può anche +controllare esplicitamente lo stato delle allocazioni (senza aspettare un +errore nelle relative funzioni) utilizzando la funzione \funcd{mprobe}, il cui +prototipo è: +\begin{prototype}{mcheck.h}{enum mcheck\_status mprobe(ptr)} + Esegue un controllo di consistenza delle allocazioni. + + \bodydesc{La funzione restituisce un codice fra quelli riportati in + tab.\ref{tab:mcheck_status_value}.} +\end{prototype} + +La funzione richiede che si passi come argomento un puntatore ad un blocco di +memoria precedentemente allocato con \func{malloc} o \func{realloc}, e +restituisce lo stesso codice di errore che si avrebbe per la funzione di +emergenza ad una successiva chiamata di una funzione di allocazione, e poi i +primi due codici che indicano rispettivamente quando tutto è a posto o il +controllo non è possibile per non aver chiamato \func{mcheck} in tempo. + +% TODO: trattare le altre funzionalità avanzate di \func{malloc}, mallopt, +% mtrace, muntrace, mallinfo e gli hook con le glibc 2.10 c'è pure malloc_info +% a sostituire mallinfo, vedi http://udrepper.livejournal.com/20948.html -Oltre al passaggio degli argomenti, un'altra modalità che permette di passare -delle informazioni che modifichino il comportamento di un programma è quello -dell'uso del cosiddetto \textit{environment} (cioè l'uso delle -\textsl{variabili di ambiente}). In questa sezione esamineremo le funzioni che -permettono di gestire argomenti ed opzioni, e quelle che consentono di -manipolare ed utilizzare le variabili di ambiente. +\section{Argomenti, ambiente ed altre proprietà di un processo} +\label{sec:proc_options} + + +In questa sezione esamineremo le funzioni che permettono di gestire gli +argomenti e le opzioni, e quelle che consentono di manipolare ed utilizzare le +variabili di ambiente. Accenneremo infine alle modalità con cui si può gestire +la localizzazione di un programma modificandone il comportamento a seconda +della lingua o del paese a cui si vuole faccia riferimento nelle sue +operazioni. \subsection{Il formato degli argomenti} \label{sec:proc_par_format} -In genere il passaggio degli argomenti al programma viene effettuato dalla -shell, che si incarica di leggere la linea di comando e di effettuarne la -scansione (il cosiddetto \textit{parsing}) per individuare le parole che la -compongono, ciascuna delle quali viene considerata un argomento. Di norma per -individuare le parole viene usato come carattere di separazione lo spazio o il -tabulatore, ma il comportamento è modificabile attraverso l'impostazione della -variabile di ambiente \cmd{IFS}. +Tutti i programmi hanno la possibilità di ricevere argomenti e opzioni quando +vengono lanciati. Il passaggio degli argomenti e delle opzioni è effettuato +attraverso gli argomenti \param{argc} e \param{argv} della funzione +\func{main}, che vengono passati al programma dalla shell (o dal processo che +esegue la \func{exec}, secondo le modalità che vedremo in +sez.~\ref{sec:proc_exec}) quando questo viene messo in esecuzione. + +In genere il passaggio di argomenti ed opzioni ad un programma viene +effettuato dalla shell, che si incarica di leggere la linea di comando e di +effettuarne la scansione (il cosiddetto \textit{parsing}) per individuare le +parole che la compongono, ciascuna delle quali potrà essere considerata un +argomento o un'opzione. Di norma per individuare le parole che andranno a +costituire la lista degli argomenti viene usato come carattere di separazione +lo spazio o il tabulatore, ma la cosa dipende ovviamente dalle modalità con +cui si effettua la scansione. \begin{figure}[htb] \centering - \includegraphics[width=13cm]{img/argv_argc} +% \includegraphics[width=13cm]{img/argv_argc} +% \includegraphics[width=13cm]{img/argv_argc} + \begin{tikzpicture}[>=stealth] + \draw (0.5,2.5) rectangle (3.5,3); + \draw (2,2.75) node {\texttt{argc = 5}}; + \draw (5,2.5) rectangle (8,3); + \draw (6.5,2.75) node {\texttt{argv[0]}}; + \draw [->] (8,2.75) -- (9,2.75); + \draw (9,2.75) node [anchor=west] {\texttt{"touch"}}; + \draw (5,2) rectangle (8,2.5); + \draw (6.5,2.25) node {\texttt{argv[1]}}; + \draw [->] (8,2.25) -- (9,2.25); + \draw (9,2.25) node [anchor=west] {\texttt{"-r"}}; + \draw (5,1.5) rectangle (8,2); + \draw (6.5,1.75) node {\texttt{argv[2]}}; + \draw [->] (8,1.75) -- (9,1.75); + \draw (9,1.75) node [anchor=west] {\texttt{"riferimento.txt"}}; + \draw (5,1.0) rectangle (8,1.5); + \draw (6.5,1.25) node {\texttt{argv[3]}}; + \draw [->] (8,1.25) -- (9,1.25); + \draw (9,1.25) node [anchor=west] {\texttt{"-m"}}; + \draw (5,0.5) rectangle (8,1.0); + \draw (6.5,0.75) node {\texttt{argv[4]}}; + \draw [->] (8,0.75) -- (9,0.75); + \draw (9,0.75) node [anchor=west] {\texttt{"questofile.txt"}}; + \draw (4.25,3.5) node{\texttt{"touch -r riferimento.txt -m questofile.txt"}}; + + \end{tikzpicture} \caption{Esempio dei valori di \param{argv} e \param{argc} generati nella scansione di una riga di comando.} \label{fig:proc_argv_argc} \end{figure} -Nella scansione viene costruito il vettore di puntatori \param{argv} inserendo -in successione il puntatore alla stringa costituente l'$n$-simo argomento; la -variabile \param{argc} viene inizializzata al numero di argomenti trovati, in -questo modo il primo argomento è sempre il nome del programma; un esempio di -questo meccanismo è mostrato in fig.~\ref{fig:proc_argv_argc}. +Indipendentemente da come viene eseguita, il risultato della scansione deve +essere la costruzione del vettore di puntatori \param{argv} in cui si devono +inserire in successione i puntatori alle stringhe costituenti i vari argomenti +ed opzioni, e della variabile \param{argc} che deve essere inizializzata al +numero di stringhe passate. Nel caso della shell questo comporta che il primo +argomento sia sempre il nome del programma; un esempio di questo meccanismo è +mostrato in fig.~\ref{fig:proc_argv_argc}. \subsection{La gestione delle opzioni} @@ -996,7 +1335,7 @@ Esegue il parsing degli argomenti passati da linea di comando riconoscendo le possibili opzioni segnalate con \param{optstring}. \bodydesc{Ritorna il carattere che segue l'opzione, \cmd{':'} se manca un - parametro all'opzione, \cmd{'?'} se l'opzione è sconosciuta, e -1 se non + parametro all'opzione, \cmd{'?'} se l'opzione è sconosciuta, e $-1$ se non esistono altre opzioni.} \end{prototype} @@ -1013,7 +1352,7 @@ due punti \texttt{':'}; nel caso di fig.~\ref{fig:proc_argv_argc} ad esempio la stringa di opzioni avrebbe dovuto contenere \texttt{"r:m"}. La modalità di uso di \func{getopt} è pertanto quella di chiamare più volte la -funzione all'interno di un ciclo, fintanto che essa non ritorna il valore -1 +funzione all'interno di un ciclo, fintanto che essa non ritorna il valore $-1$ che indica che non ci sono più opzioni. Nel caso si incontri un'opzione non dichiarata in \param{optstring} viene ritornato il carattere \texttt{'?'} mentre se un'opzione che lo richiede non è seguita da un parametro viene @@ -1065,42 +1404,41 @@ opzioni sono spostati in coda al vettore. Oltre a questa esistono altre due modalità di gestire gli elementi di \param{argv}; se \param{optstring} inizia con il carattere \texttt{'+'} (o è impostata la variabile di ambiente \macro{POSIXLY\_CORRECT}) la scansione viene fermata non appena si incontra un -elemento che non è un'opzione. L'ultima modalità, usata quando un programma -può gestire la mescolanza fra opzioni e argomenti, ma se li aspetta in un -ordine definito, si attiva quando \param{optstring} inizia con il carattere -\texttt{'-'}. In questo caso ogni elemento che non è un'opzione viene -considerato comunque un'opzione e associato ad un valore di ritorno pari ad 1, -questo permette di identificare gli elementi che non sono opzioni, ma non -effettua il riordinamento del vettore \param{argv}. - +elemento che non è un'opzione. -\subsection{Opzioni in formato esteso} -\label{sec:proc_opt_extended} +L'ultima modalità, usata quando un programma può gestire la mescolanza fra +opzioni e argomenti, ma se li aspetta in un ordine definito, si attiva +quando \param{optstring} inizia con il carattere \texttt{'-'}. In questo caso +ogni elemento che non è un'opzione viene considerato comunque un'opzione e +associato ad un valore di ritorno pari ad 1, questo permette di identificare +gli elementi che non sono opzioni, ma non effettua il riordinamento del +vettore \param{argv}. -Un'estensione di questo schema è costituita dalle cosiddette -\textit{long-options} espresse nella forma \cmd{-{}-option=parameter}, anche -la gestione di queste ultime è stata standardizzata attraverso l'uso di una -versione estesa di \func{getopt}. - -(NdA: questa parte verrà inserita in seguito). -% TODO opzioni in formato esteso \subsection{Le variabili di ambiente} \label{sec:proc_environ} -Oltre agli argomenti passati a linea di comando ogni processo riceve dal -sistema un \textsl{ambiente}, nella forma di una lista di variabili (detta -\textit{environment list}) messa a disposizione dal processo, e costruita -nella chiamata alla funzione \func{exec} quando questo viene lanciato. - -Come per la lista degli argomenti anche questa lista è un vettore di puntatori -a caratteri, ciascuno dei quali punta ad una stringa, terminata da un +Oltre agli argomenti passati a linea di comando esiste un'altra modalità che +permette di trasferire ad un processo delle informazioni in modo da +modificarne il comportamento. Ogni processo infatti riceve dal sistema, oltre +alle variabili \param{argv} e \param{argc} anche un \textsl{ambiente} (in +inglese \textit{environment}); questo viene espresso nella forma di una lista +(chiamata \textit{environment list}) delle cosiddette \textsl{variabili di + ambiente}, i valori di queste variabili possono essere poi usati dal +programma. + +Anche in questo caso la lista delle \textsl{variabili di ambiente} deve essere +costruita ed utilizzata nella chiamata alla funzione \func{exec} (torneremo su +questo in sez.~\ref{sec:proc_exec}) quando questo viene lanciato. Come per la +lista degli argomenti anche questa lista è un vettore di puntatori a +caratteri, ciascuno dei quali punta ad una stringa, terminata da un \val{NULL}. A differenza di \code{argv[]} in questo caso non si ha una lunghezza del vettore data da un equivalente di \param{argc}, ma la lista è terminata da un puntatore nullo. L'indirizzo della lista delle variabili di ambiente è passato attraverso la -variabile globale \var{environ}, a cui si può accedere attraverso una semplice +variabile globale \var{environ}, che viene definita automaticamente per +cisascun processo, e a cui si può accedere attraverso una semplice dichiarazione del tipo: \includecodesnip{listati/env_ptr.c} un esempio della struttura di questa lista, contenente alcune delle variabili @@ -1108,19 +1446,47 @@ pi fig.~\ref{fig:proc_envirno_list}. \begin{figure}[htb] \centering - \includegraphics[width=13cm]{img/environ_var} +% \includegraphics[width=15 cm]{img/environ_var} + \begin{tikzpicture}[>=stealth] + \draw (2,3.5) node {\textsf{Environment pointer}}; + \draw (6,3.5) node {\textsf{Environment list}}; + \draw (10.5,3.5) node {\textsf{Environment string}}; + \draw (0.5,2.5) rectangle (3.5,3); + \draw (2,2.75) node {\texttt{environ}}; + \draw [->] (3.5,2.75) -- (4.5,2.75); + \draw (4.5,2.5) rectangle (7.5,3); + \draw (6,2.75) node {\texttt{environ[0]}}; + \draw (4.5,2) rectangle (7.5,2.5); + \draw (6,2.25) node {\texttt{environ[1]}}; + \draw (4.5,1.5) rectangle (7.5,2); + \draw (4.5,1) rectangle (7.5,1.5); + \draw (4.5,0.5) rectangle (7.5,1); + \draw (4.5,0) rectangle (7.5,0.5); + \draw (6,0.25) node {\texttt{NULL}}; + \draw [->] (7.5,2.75) -- (8.5,2.75); + \draw (8.5,2.75) node[right] {\texttt{HOME=/home/piccardi}}; + \draw [->] (7.5,2.25) -- (8.5,2.25); + \draw (8.5,2.25) node[right] {\texttt{PATH=:/bin:/usr/bin}}; + \draw [->] (7.5,1.75) -- (8.5,1.75); + \draw (8.5,1.75) node[right] {\texttt{SHELL=/bin/bash}}; + \draw [->] (7.5,1.25) -- (8.5,1.25); + \draw (8.5,1.25) node[right] {\texttt{EDITOR=emacs}}; + \draw [->] (7.5,0.75) -- (8.5,0.75); + \draw (8.5,0.75) node[right] {\texttt{OSTYPE=linux-gnu}}; + \end{tikzpicture} \caption{Esempio di lista delle variabili di ambiente.} \label{fig:proc_envirno_list} \end{figure} Per convenzione le stringhe che definiscono l'ambiente sono tutte del tipo -\textsl{\texttt{nome=valore}}. Inoltre alcune variabili, come quelle elencate -in fig.~\ref{fig:proc_envirno_list}, sono definite dal sistema per essere usate +\textsl{\texttt{nome=valore}} ed in questa forma che le funzioni di gestione +che vedremo a breve se le aspettano, se pertanto si dovesse costruire +manualemente un ambiente si abbia cura di rispettare questa convenzione. +Inoltre alcune variabili, come quelle elencate in +fig.~\ref{fig:proc_envirno_list}, sono definite dal sistema per essere usate da diversi programmi e funzioni: per queste c'è l'ulteriore convenzione di -usare nomi espressi in caratteri maiuscoli.\footnote{la convenzione vuole che - si usino dei nomi maiuscoli per le variabili di ambiente di uso generico, i - nomi minuscoli sono in genere riservati alle variabili interne degli script - di shell.} +usare nomi espressi in caratteri maiuscoli.\footnote{ma si tratta solo di una + convenzione, niente vieta di usare caratteri minuscoli.} Il kernel non usa mai queste variabili, il loro uso e la loro interpretazione è riservata alle applicazioni e ad alcune funzioni di libreria; in genere esse @@ -1130,19 +1496,27 @@ configurazione. queste variabili al programma messo in esecuzione attraverso un uso opportuno delle relative chiamate (si veda sez.~\ref{sec:proc_exec}). -La shell ad esempio ne usa molte per il suo funzionamento (come \texttt{PATH} -per la ricerca dei comandi, o \texttt{IFS} per la scansione degli argomenti), -e alcune di esse (come \texttt{HOME}, \texttt{USER}, ecc.) sono definite al -login (per i dettagli si veda sez.~\ref{sec:sess_login}). In genere è cura -dell'amministratore definire le opportune variabili di ambiente in uno script -di avvio. Alcune servono poi come riferimento generico per molti programmi -(come \texttt{EDITOR} che indica l'editor preferito da invocare in caso di -necessità). +La shell ad esempio ne usa molte per il suo funzionamento, come \texttt{PATH} +per indicare la lista delle directory in cui effettuare la ricerca dei comandi +o \texttt{PS1} per impostare il proprio \textit{prompt}. Alcune di esse, come +\texttt{HOME}, \texttt{USER}, ecc. sono invece definite al login (per i +dettagli si veda sez.~\ref{sec:sess_login}), ed in genere è cura della propria +distribuzione definire le opportune variabili di ambiente in uno script di +avvio. Alcune servono poi come riferimento generico per molti programmi, come +\texttt{EDITOR} che indica l'editor preferito da invocare in caso di +necessità. Una in particolare, \texttt{LANG}, serve a controllare la +localizzazione del programma (su cui torneremo in +sez.~\ref{sec:proc_localization}) per adattarlo alla lingua ed alle convezioni +dei vari paesi. Gli standard POSIX e XPG3 definiscono alcune di queste variabili (le più comuni), come riportato in tab.~\ref{tab:proc_env_var}. GNU/Linux le supporta -tutte e ne definisce anche altre: per una lista più completa si può -controllare \cmd{man 5 environ}. +tutte e ne definisce anche altre, in particolare poi alcune funzioni di +libreria prevedono la presenza di specifiche variabili di ambiente che ne +modificano il comportamento, come quelle usate per indicare una localizzazione +e quelle per indicare un fuso orario; una lista più completa che comprende +queste ed ulteriori variabili si può ottenere con il comando \cmd{man 7 + environ}. \begin{table}[htb] \centering @@ -1235,19 +1609,21 @@ ambiente, i loro prototipi sono i seguenti: \funcdecl{int putenv(char *string)} Aggiunge la stringa \param{string} all'ambiente. - \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e -1 per un + \bodydesc{Entrambe le funzioni ritornano 0 in caso di successo e $-1$ per un errore, che è sempre \errval{ENOMEM}.} \end{functions} -\noindent la terza, \funcd{unsetenv}, serve a cancellare una variabile di -ambiente; il suo prototipo è: + +La terza funzione della lista, \funcd{unsetenv}, serve a cancellare una +variabile dall'ambiente, il suo prototipo è: \begin{functions} \headdecl{stdlib.h} \funcdecl{void unsetenv(const char *name)} Rimuove la variabile di ambiente \param{name}. \end{functions} -\noindent questa funzione elimina ogni occorrenza della variabile specificata; -se essa non esiste non succede nulla. Non è prevista (dato che la funzione è + +\noindent la funzione elimina ogni occorrenza della variabile specificata; se la +variabile non esiste non succede nulla. Non è prevista (dato che la funzione è \ctyp{void}) nessuna segnalazione di errore. Per modificare o aggiungere una variabile di ambiente si possono usare sia @@ -1261,34 +1637,37 @@ La seconda funzione prende come argomento una stringa analoga a quella restituita da \func{getenv}, e sempre nella forma \code{NOME=valore}. Se la variabile specificata non esiste la stringa sarà aggiunta all'ambiente, se invece esiste il suo valore sarà impostato a quello specificato da -\param{string}. Si tenga presente che, seguendo lo standard SUSv2, le -\acr{glibc} successive alla versione 2.1.2 aggiungono\footnote{il - comportamento è lo stesso delle vecchie \acr{libc4} e \acr{libc5}; nelle - \acr{glibc}, dalla versione 2.0 alla 2.1.1, veniva invece fatta una copia, - seguendo il comportamento di BSD4.4; dato che questo può dar luogo a perdite - di memoria e non rispetta lo standard. Il comportamento è stato modificato a - partire dalle 2.1.2, eliminando anche, sempre in conformità a SUSv2, - l'attributo \direct{const} dal prototipo.} \param{string} alla lista delle -variabili di ambiente; pertanto ogni cambiamento alla stringa in questione si -riflette automaticamente sull'ambiente, e quindi si deve evitare di passare a -questa funzione una variabile automatica (per evitare i problemi esposti in -sez.~\ref{sec:proc_auto_var}). - -Si tenga infine presente che se si passa a \func{putenv} solo il nome di una -variabile (cioè \param{string} è nella forma \texttt{NAME} e non contiene un -carattere \texttt{'='}) allora questa viene cancellata dall'ambiente. Infine -se la chiamata di \func{putenv} comporta la necessità di allocare una nuova -versione del vettore \var{environ} questo sarà allocato, ma la versione -corrente sarà deallocata solo se anch'essa è risultante da un'allocazione -fatta in precedenza da un'altra \func{putenv}. Questo perché il vettore delle -variabili di ambiente iniziale, creato dalla chiamata ad \func{exec} (vedi -sez.~\ref{sec:proc_exec}) è piazzato al di sopra dello \itindex{stack} stack, -(vedi fig.~\ref{fig:proc_mem_layout}) e non nello \itindex{heap} \textit{heap} -e non può essere deallocato. Inoltre la memoria associata alle variabili di -ambiente eliminate non viene liberata. - -L'ultima funzione è \funcd{clearenv}, che viene usata per cancellare -completamente tutto l'ambiente; il suo prototipo è: +\param{string}. + +Si tenga presente che, seguendo lo standard SUSv2, le \acr{glibc} successive +alla versione 2.1.2 aggiungono \param{string} alla lista delle variabili di +ambiente;\footnote{il comportamento è lo stesso delle vecchie \acr{libc4} e + \acr{libc5}; nelle \acr{glibc}, dalla versione 2.0 alla 2.1.1, veniva invece + fatta una copia, seguendo il comportamento di BSD4.4; dato che questo può + dar luogo a perdite di memoria e non rispetta lo standard. Il comportamento + è stato modificato a partire dalle 2.1.2, eliminando anche, sempre in + conformità a SUSv2, l'attributo \direct{const} dal prototipo.} pertanto ogni +cambiamento alla stringa in questione si riflette automaticamente +sull'ambiente, e quindi si deve evitare di passare a questa funzione una +variabile automatica (per evitare i problemi esposti in +sez.~\ref{sec:proc_auto_var}). Si tenga infine presente che se si passa a +\func{putenv} solo il nome di una variabile (cioè \param{string} è nella forma +\texttt{NAME} e non contiene un carattere \texttt{'='}) allora questa viene +cancellata dall'ambiente. + +Infine quando chiamata a \func{putenv} comporta la necessità di creare una +nuova versione del vettore \var{environ} questo sarà allocato automaticamente, +ma la versione corrente sarà deallocata solo se anch'essa è risultante da +un'allocazione fatta in precedenza da un'altra \func{putenv}. Questo avviene +perché il vettore delle variabili di ambiente iniziale, creato dalla chiamata +ad \func{exec} (vedi sez.~\ref{sec:proc_exec}) è piazzato nella memoria al di +sopra dello \itindex{stack} stack, (vedi fig.~\ref{fig:proc_mem_layout}) e non +nello \itindex{heap} \textit{heap} e quindi non può essere deallocato. +Inoltre la memoria associata alle variabili di ambiente eliminate non viene +liberata. + +L'ultima funzione per la gestione dell'ambiente è \funcd{clearenv}, che viene +usata per cancellare completamente tutto l'ambiente; il suo prototipo è: \begin{functions} \headdecl{stdlib.h} @@ -1305,6 +1684,39 @@ ambiente che pu alla cancellazione di tutto l'ambiente per costruirne una versione ``\textsl{sicura}'' da zero. +\subsection{La localizzazione} +\label{sec:proc_localization} + +Abbiamo accennato in sez.~\ref{sec:proc_environ} come la variabile di ambiente +\texttt{LANG} sia usata per indicare ai processi il valore della cosiddetta +\textsl{localizzazione}. Si tratta di una funzionalità fornita dalle librerie +di sistema\footnote{prenderemo in esame soltanto il caso delle \acr{glibc}.} +che consente di gestire in maniera automatica sia la lingua in cui vengono +stampati i vari messaggi (come i messaggi associati agli errori che vedremo in +sez.~\ref{sec:sys_strerror}) che le convenzioni usate nei vari paesi per una +serie di aspetti come il formato dell'ora, quello delle date, gli ordinamenti +alfabetici, le espressioni della valute, ecc. + +La localizzazione di un programma si può selezionare con la + + +In realtà perché un programma sia effettivamente localizzato non è sufficiente + +% TODO trattare, quando ci sarà tempo, setlocale ed il resto + + +%\subsection{Opzioni in formato esteso} +%\label{sec:proc_opt_extended} + +%Oltre alla modalità ordinaria di gestione delle opzioni trattata in +%sez.~\ref{sec:proc_opt_handling} le \acr{glibc} forniscono una modalità +%alternativa costituita dalle cosiddette \textit{long-options}, che consente di +%esprimere le opzioni in una forma più descrittiva che nel caso più generale è +%qualcosa del tipo di ``\texttt{-{}-option-name=parameter}''. + +%(NdA: questa parte verrà inserita in seguito). + +% TODO opzioni in formato esteso \section{Problematiche di programmazione generica} \label{sec:proc_gen_prog} @@ -1373,7 +1785,7 @@ dette funzioni possono accedere ai loro argomenti. L'accesso viene pertanto realizzato a livello delle librerie standard del C che provvedono gli strumenti adeguati. L'uso di una \textit{variadic function} prevede quindi tre punti: -\begin{itemize} +\begin{itemize*} \item \textsl{Dichiarare} la funzione come \textit{variadic} usando un prototipo che contenga una \textit{ellipsis}. \item \textsl{Definire} la funzione come \textit{variadic} usando la stessa @@ -1381,7 +1793,7 @@ tre punti: gestione di un numero variabile di argomenti. \item \textsl{Invocare} la funzione specificando prima gli argomenti fissi, ed a seguire quelli addizionali. -\end{itemize} +\end{itemize*} Lo standard ISO C prevede che una \index{variadic} \textit{variadic function} abbia sempre almeno un argomento fisso; prima di effettuare la dichiarazione @@ -1411,7 +1823,7 @@ L'unica modalit sequenziale; essi verranno estratti dallo \itindex{stack} \textit{stack} secondo l'ordine in cui sono stati scritti. Per fare questo in \file{stdarg.h} sono definite delle apposite macro; la procedura da seguire è la seguente: -\begin{enumerate} +\begin{enumerate*} \item Inizializzare un puntatore alla lista degli argomenti di tipo \macro{va\_list} attraverso la macro \macro{va\_start}. \item Accedere ai vari argomenti opzionali con chiamate successive alla macro @@ -1419,7 +1831,7 @@ sono definite delle apposite macro; la procedura da seguire il secondo e così via. \item Dichiarare la conclusione dell'estrazione degli argomenti invocando la macro \macro{va\_end}. -\end{enumerate} +\end{enumerate*} In generale è perfettamente legittimo richiedere meno argomenti di quelli che potrebbero essere stati effettivamente forniti, e nella esecuzione delle \macro{va\_arg} ci si può fermare in qualunque momento ed i restanti argomenti @@ -1507,7 +1919,7 @@ Esistono varie modalit immediate è quella di specificare il numero degli argomenti opzionali come uno degli argomenti fissi. Una variazione di questo metodo è l'uso di un argomento per specificare anche il tipo degli argomenti (come fa la stringa di formato -per \func{printf}). +per \func{printf}). Una modalità diversa, che può essere applicata solo quando il tipo degli argomenti lo rende possibile, è quella che prevede di usare un valore speciale @@ -1693,7 +2105,7 @@ dichiarandole tutte come \direct{volatile}.\footnote{la direttiva % LocalWords: SUCCESS FAILURE void atexit stream fclose unistd descriptor init % LocalWords: SIGCHLD wait function glibc SunOS arg argp execve fig high kb Mb % LocalWords: memory alpha swap table printf Unit MMU paging fault SIGSEGV BSS -% LocalWords: multitasking segmentation text segment NULL Block Started Symbol +% LocalWords: multitasking text segment NULL Block Started Symbol % LocalWords: heap stack calling convention size malloc calloc realloc nmemb % LocalWords: ENOMEM ptr uClib cfree error leak smartpointers hook Dmalloc brk % LocalWords: Gray Watson Electric Fence Bruce Perens sbrk longjmp SUSv BSD ap @@ -1707,7 +2119,8 @@ dichiarandole tutte come \direct{volatile}.\footnote{la direttiva % LocalWords: clearenv libc value overwrite string reference result argument % LocalWords: socket variadic ellipsis header stdarg execl self promoting last % LocalWords: float double short register type dest src extern setjmp jmp buf -% LocalWords: env return if while sottoprocesso Di +% LocalWords: env return if while Di page cdecl +% LocalWords: environment %%% Local Variables: %%% mode: latex