X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=blobdiff_plain;f=process.tex;h=8d85fcb4a736778d776ec69f621a780ea2234b76;hp=9d749c03f2280a6f22993607f2ec8b830eafcdf8;hb=0196c376e39fc18f8cd5e7fef47b61264f943faf;hpb=6ffcce00491cea4ac7c621fe412269f15ee23f57 diff --git a/process.tex b/process.tex index 9d749c0..8d85fcb 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-2008 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 @@ -82,8 +82,8 @@ controllo direttamente alla funzione di conclusione dei processi del kernel. Oltre alla conclusione ``\textsl{normale}'' esiste anche la possibilità di una conclusione ``\textsl{anomala}'' del programma a causa della ricezione di un -segnale (si veda cap.~\ref{cha:signals}) o della chiamata alla funzione -\func{abort}; torneremo su questo in sez.~\ref{sec:proc_termination}. +segnale (tratteremo i segnali in cap.~\ref{cha:signals}) o della chiamata alla +funzione \func{abort}; torneremo su questo in sez.~\ref{sec:proc_termination}. Il valore di ritorno della funzione \func{main}, o quello usato nelle chiamate ad \func{exit} e \func{\_exit}, viene chiamato \textsl{stato di uscita} (o @@ -234,7 +234,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 +373,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 +443,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 +458,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} @@ -566,13 +624,13 @@ 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*} +\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 @@ -632,7 +690,6 @@ ricompilare il programma,\footnote{esempi sono \textit{Dmalloc} \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 @@ -640,11 +697,10 @@ 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 è: \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 +728,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,14 +735,29 @@ 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. @@ -704,15 +765,22 @@ La prima funzione 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 è: @@ -916,6 +984,7 @@ ci si scrive sopra. \itindend{memory~locking} + % TODO documentare \func{madvise} % TODO documentare \func{mincore} @@ -925,7 +994,11 @@ ci si scrive sopra. % \subsection{Gestione avanzata dell'allocazione della memoria} % \label{sec:proc_mem_malloc_custom} + % TODO: trattare le funzionalità avanzate di \func{malloc} +% TODO: trattare \func{memalign} +% TODO: trattare \func{valloc} +% TODO: trattare \func{posix\_memalign} @@ -1074,17 +1147,6 @@ questo permette di identificare gli elementi che non sono opzioni, ma non effettua il riordinamento del vettore \param{argv}. -\subsection{Opzioni in formato esteso} -\label{sec:proc_opt_extended} - -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} @@ -1306,6 +1368,21 @@ alla cancellazione di tutto l'ambiente per costruirne una versione ``\textsl{sicura}'' da zero. +\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} @@ -1693,7 +1770,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 +1784,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