From: Simone Piccardi Date: Wed, 27 Feb 2002 11:47:52 +0000 (+0000) Subject: Correzioni multiple da Daniele Masini X-Git-Url: https://gapil.gnulinux.it/gitweb/?p=gapil.git;a=commitdiff_plain;h=2bb235e9ba8e8d532251205d30b82455dc119894 Correzioni multiple da Daniele Masini --- diff --git a/ChangeLog b/ChangeLog index e343f4c..f1a6a7b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2002-02-27 Simone Piccardi + + * pref.tex, intro.tex, process.tex, prochand.tex: Correzioni + multiple da Daniele Masini. + 2001-02-27 Simone Piccardi * network.tex: completata (si fa per dire) la parte introduttiva. diff --git a/intro.tex b/intro.tex index 5e9ade0..b03d1e3 100644 --- a/intro.tex +++ b/intro.tex @@ -6,7 +6,7 @@ cui fornire una base di comprensione mirata a sottolineare le peculiarità del sistema che sono più rilevanti per quello che riguarda la programmazione. -Dopo una introduzione sulle caratteristiche principali di un sistema di tipo +Dopo un'introduzione sulle caratteristiche principali di un sistema di tipo unix passeremo ad illustrare alcuni dei concetti base dell'architettura di GNU/Linux (che sono comunque comuni a tutti i sistemi \textit{unix-like}) ed introdurremo alcuni degli standard principali a cui viene fatto riferimento. @@ -79,7 +79,7 @@ Uno dei concetti fondamentali su cui si basa l'architettura dei sistemi unix quello della distinzione fra il cosiddetto \textit{user space}, che contraddistingue l'ambiente in cui vengono eseguiti i programmi, e il \textit{kernel space}, che è l'ambiente in cui viene eseguito il kernel. Ogni -programma vede se stesso come se avesse la piena disponibilità della CPU e +programma vede sé stesso come se avesse la piena disponibilità della CPU e della memoria ed è, salvo i meccanismi di comunicazione previsti dall'architettura, completamente ignaro del fatto che altri programmi possono essere messi in esecuzione dal kernel. @@ -138,9 +138,9 @@ si aspetta da un sistema operativo. Come accennato le interfacce con cui i programmi possono accedere all'hardware vanno sotto il nome di chiamate al sistema (le cosiddette \textit{system call}), si tratta di un insieme di funzioni, che un programma può chiamare, -per le quali viene generata una interruzione processo ed il controllo passa -dal programma al kernel. Sarà poi quest'ultimo che (oltre a compiere una serie -di operazioni interne come la gestione del multitasking e l'allocazione della +per le quali viene generata un'interruzione processo ed il controllo passa dal +programma al kernel. Sarà poi quest'ultimo che (oltre a compiere una serie di +operazioni interne come la gestione del multitasking e l'allocazione della memoria) eseguirà la funzione richiesta in \textit{kernel space} restituendo i risultati al chiamante. @@ -193,7 +193,7 @@ danneggiarsi a vicenda o danneggiare il sistema. Ad ogni utente è dato un nome \textit{username}, che è quello che viene richiesto all'ingresso nel sistema dalla procedura di \textit{login}. Questa -procedura si incarica di verificare la identità dell'utente, in genere +procedura si incarica di verificare l'identità dell'utente, in genere attraverso la richiesta di una parola d'ordine, anche se sono possibili meccanismi diversi\footnote{Ad esempio usando la libreria PAM (\textit{Pluggable Autentication Methods}) è possibile astrarre @@ -202,7 +202,7 @@ meccanismi diversi\footnote{Ad esempio usando la libreria PAM Eseguita la procedura di riconoscimento in genere il sistema manda in esecuzione un programma di interfaccia (che può essere la \textit{shell} su -terminale o una interfaccia grafica) che mette a disposizione dell'utente un +terminale o un'interfaccia grafica) che mette a disposizione dell'utente un meccanismo con cui questo può impartire comandi o eseguire altri programmi. Ogni utente appartiene anche ad almeno un gruppo (il cosiddetto @@ -285,14 +285,13 @@ usare le varie estensioni al linguaggio e al preprocessore da esso supportate. \label{sec:intro_posix} Uno standard più attinente al sistema nel suo complesso (e che concerne sia il -kernel che le librerie e` lo standard POSIX. Esso prende origine dallo -standard ANSI C, che contiene come sottoinsieme, prevedendo ulteriori capacità -per le funzioni in esso definite, ed aggiungendone di nuove. Le estensioni -principali sono +kernel che le librerie è lo standard POSIX. Esso prende origine dallo standard +ANSI C, che contiene come sottoinsieme, prevedendo ulteriori capacità per le +funzioni in esso definite, ed aggiungendone di nuove. In realtà POSIX è una famiglia di standard diversi, il cui nome, suggerito da Richard Stallman, sta per \textit{Portable Operating System Interface}, ma la -X finale denuncia la sua stretta relazione con i sistemi unix. Esso nasce dal +X finale denuncia la sua stretta relazione con i sistemi Unix. Esso nasce dal lavoro dell'IEEE (\textit{Institute of Electrical and Electronics Engeneers}) che ne produsse una prima versione, nota come IEEE 1003.1-1988, mirante a standardizzare l'interfaccia con il sistema operativo. @@ -302,12 +301,12 @@ libreria, e in seguito sono stati prodotti anche altri standard per la shell e le utility di sistema (1003.2), per le estensioni realtime e per i thread (1003.1d e 1003.1c) e vari altri. -Benché lo standard POSIX sia basato sui sistemi unix esso definisce comunque -una interfaccia e non fa riferimento ad una specifica implementazione (ad -esempio esiste anche una implementazione di questo standard pure sotto Windows -NT). Lo standard si è evoluto nel tempo ed una versione più aggiornata (quella -che viene normalmente denominata POSIX.1) è stata rilasciata come standard -internazionale con la sigla ISO/IEC 9945-1:1996. +Benché lo standard POSIX sia basato sui sistemi Unix esso definisce comunque +un'interfaccia e non fa riferimento ad una specifica implementazione (ad +esempio esiste un'implementazione di questo standard anche sotto Windows NT). +Lo standard si è evoluto nel tempo ed una versione più aggiornata (quella che +viene normalmente denominata POSIX.1) è stata rilasciata come standard +internazionale con la sigla ISO/IEC 9945-1:1996. Le \acr{glibc} implementano tutte le funzioni definite nello standard POSIX.1, e Linux; @@ -317,14 +316,14 @@ e Linux; \label{sec:intro_xopen} Il consorzio X/Open nacque nel 1984 come consorzio di venditori di sistemi -unix per giungere ad una armonizzazione delle varie implementazioni. Per far +unix per giungere ad un'armonizzazione delle varie implementazioni. Per far questo iniziò a pubblicare una serie di documentazioni e specifiche sotto il nome di \textit{X/Open Portability Guide} (a cui di norma si fa riferimento con l'abbreviazione XPGn). Nel 1989 produsse una terza versione di questa guida particolarmente -voluminosa (la \textit{X/Open Portability Guide, Issue 3}), contenente una -ulteriore standardizzazione dell'interfaccia sistema unix, che venne presa +voluminosa (la \textit{X/Open Portability Guide, Issue 3}), contenente +un'ulteriore standardizzazione dell'interfaccia sistema unix, che venne presa come riferimento da vari produttori. Questo standard, detto anche XPG3 dal nome della suddetta guida, è sempre @@ -396,10 +395,11 @@ marchio depositato, sviluppandone una serie di versioni diverse; nel 1983 la versione supportata ufficialmente venne rilasciata al pubblico con il nome di Unix System V. Negli anni successivi l'AT/T proseguì lo sviluppo rilasciando varie versioni con aggiunte e integrazioni; nel 1989 un accordo fra vari -venditori (AT/T, Sun, HP, e altro) portò ad una versione che provvedeva una -unificazione dell interfacce comprendente Xenix e BSD, la System V release 4. +venditori (AT/T, Sun, HP, e altro) portò ad una versione che provvedeva +un'unificazione dell interfacce comprendente Xenix e BSD, la System V release +4. -La interfaccia di questa ultima release è descritta in un documento dal titolo +L'interfaccia di questa ultima release è descritta in un documento dal titolo \textit{System V Interface Description}, o SVID; spesso però si riferimento a questo standard con il nome della sua implementazione, usando la sigla SVr4. @@ -436,8 +436,8 @@ nessuna funzione non riconosciuta dalle specifiche standard ISO per il C. Per attivare le varie opzioni è possibile definire le macro di preprocessore, che controllano le funzionalità che le \acr{glibc} possono mettere a -disposizione questo può essere fatto attraverso l'opzione \cmd{-D} del -compilatore, ma è buona norma inserire gli opportuni \texttt{\#define} nei +disposizione: questo può essere fatto attraverso l'opzione \cmd{-D} del +compilatore, ma è buona norma inserire gli opportuni \code{\#define} nei propri header file. Le macro disponibili per i vari standard sono le seguenti: @@ -480,21 +480,21 @@ Le macro disponibili per i vari standard sono le seguenti: disponibili in BSD e SVID. Se il valore della macro è posto a 500 questo include anche le nuove definizioni introdotte con la \textit{Single Unix Specification, version 2}, cioè Unix98. -\item[\macro{\_XOPEN\_SOURCE\_EXTENDED}] questa macro si attivano le ulteriori - funzionalità necessarie a esse conformi al rilascio del marchio - \textit{X/Open Unix} -\item[\macro{\_ISOC99\_SOURCE}] questa macro si attivano le +\item[\macro{\_XOPEN\_SOURCE\_EXTENDED}] definendo questa macro si attivano le + ulteriori funzionalità necessarie ad essere conformi al rilascio del marchio + \textit{X/Open Unix}. +\item[\macro{\_ISOC99\_SOURCE}] definendo questa macro si attivano le funzionalità previste per la revisione delle librerie standard del C denominato ISO C99. Dato che lo standard non è ancora adottato in maniera - ampia queste non sona abilitate automaticamente, ma le \acr{glibc} ha già - una implementazione completa che può essere attivata definendo questa macro. -\item[\macro{\_LARGEFILE\_SOURCE}] questa macro si attivano le + ampia queste non sono abilitate automaticamente, ma le \acr{glibc} hanno già + un'implementazione completa che può essere attivata definendo questa macro. +\item[\macro{\_LARGEFILE\_SOURCE}] definendo questa macro si attivano le funzionalità per il supporto dei file di grandi dimensioni (il \textit{Large - File Support} o LFS) con indici e dimensioni a 64 bit. -\item[\macro{\_GNU\_SOURCE}] questa macro si attivano tutte le funzionalità - disponibili: ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, X/Open, LFS più - le estensioni specifiche GNU. Nel caso in cui BSD e POSIX confliggono viene - data la precedenza a POSIX. + File Support} o LFS) con indici e dimensioni a 64 bit. +\item[\macro{\_GNU\_SOURCE}] definendo questa macro si attivano tutte le + funzionalità disponibili: ISO C89, ISO C99, POSIX.1, POSIX.2, BSD, SVID, + X/Open, LFS più le estensioni specifiche GNU. Nel caso in cui BSD e POSIX + confliggano viene data la precedenza a POSIX. \end{basedescript} In particolare è da sottolineare che le \acr{glibc} supportano alcune diff --git a/pref.tex b/pref.tex index 60410b1..31adf17 100644 --- a/pref.tex +++ b/pref.tex @@ -9,10 +9,10 @@ possibilit senza la presenza di un valido manuale che sia altrettanto liberamente disponibile. -E, come per il software libero, è anche in questo caso è di fondamentale -importanza la libertà di accedere ai sorgenti (e non solo al risultato -finale, sia questo una stampa o un file formattato) e la libertà di -modificarli per apportarvi migliorie, aggiornamenti, etc. +E, come per il software libero, anche in questo caso è di fondamentale +importanza la libertà di accedere ai sorgenti (e non solo al risultato finale, +sia questo una stampa o un file formattato) e la libertà di modificarli per +apportarvi migliorie, aggiornamenti, etc. Per questo la Free Software Foundation ha approntato una licenza apposita per la documentazione, che tiene conto delle differenze che restano fra un testo e @@ -64,7 +64,7 @@ linguaggio, e di quanto necessario per scrivere, compilare ed eseguire un programma. Infine, dato che lo scopo del progetto è la produzione di un libro, si è -scelto di usare LaTex come "ambiente di sviluppo" del medesimo, sia per +scelto di usare \LaTeX\ come "ambiente di sviluppo" del medesimo, sia per l'impareggiabile qualità tipografica ottenibile, che per la congruenza dello strumento, tanto sul piano pratico, quanto su quello filosofico. diff --git a/process.tex b/process.tex index a574eb3..935f34e 100644 --- a/process.tex +++ b/process.tex @@ -1,26 +1,26 @@ \chapter{L'interfaccia base con i processi} \label{cha:process_interface} -Come accennato nell'introduzione il processo è l'unità di base con cui un -sistema unix-like alloca ed utilizza le risorse. Questo capitolo tratterà -l'interfaccia base fra il sistema e i processi, come vengono passati i -parametri, come viene gestita e allocata la memoria, come un processo può +Come accennato nell'introduzione il \textsl{processo} è l'unità di base con +cui un sistema unix-like alloca ed utilizza le risorse. Questo capitolo +tratterà l'interfaccia base fra il sistema e i processi, come vengono passati +i parametri, come viene gestita e allocata la memoria, come un processo può richiedere servizi al sistema e cosa deve fare quando ha finito la sua esecuzione. Nella sezione finale accenneremo ad alcune problematiche generiche di programmazione. In genere un programma viene eseguito quando un processo lo fa partire -eseguendo una funzione della famiglia \func{exec}; torneremo su questo e -sulla creazione e gestione dei processi nel prossimo capitolo. In questo +eseguendo una funzione della famiglia \func{exec}; torneremo su questo e sulla +creazione e gestione dei processi nel prossimo capitolo. In questo affronteremo l'avvio e il funzionamento di un singolo processo partendo dal -punto di vista del programma che viene messo in esecuzione. +punto di vista del programma che viene messo in esecuzione. \section{Esecuzione e conclusione di un programma} Uno dei concetti base di Unix è che un processo esegue sempre uno ed un solo programma: si possono avere più processi che eseguono lo stesso programma ma -ciascun processo vedrà la sua copia del codice (in realtà il kernel fa si che +ciascun processo vedrà la sua copia del codice (in realtà il kernel fa sì che 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 @@ -31,7 +31,7 @@ tutti gli altri\footnote{questo non \subsection{La funzione \func{main}} \label{sec:proc_main} -Quando un programma viene lanciato il kernel esegue una opportuna routine di +Quando un programma viene lanciato il kernel esegue un'opportuna routine di avvio, usando il programma \cmd{ld-linux.so}. Questo programma prima carica le librerie condivise che servono al programma, poi effettua il link dinamico del codice e alla fine lo esegue. Infatti, a meno di non aver specificato il @@ -43,7 +43,7 @@ page 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 -si suppone iniziale l'esecuzione; in ogni caso senza questa funzione lo stesso +si suppone iniziare l'esecuzione; in ogni caso senza questa funzione lo stesso linker darebbe luogo ad errori. Lo standard ISO C specifica che la funzione \func{main} può non avere @@ -92,7 +92,7 @@ della funzione \func{main} senza ritornare esplicitamente si ha un valore di uscita indefinito, è pertanto consigliabile di concludere sempre in maniera esplicita detta funzione. -Una altra convenzione riserva i valori da 128 a 256 per usi speciali: ad +Un'altra convenzione riserva i valori da 128 a 256 per usi speciali: ad esempio 128 viene usato per indicare l'incapacità di eseguire un altro programma in un sottoprocesso. Benché questa convenzione non sia universalmente seguita è una buona idea tenerne conto. @@ -114,9 +114,9 @@ valori di tipo \type{int} 0 e 1. \subsection{Le funzioni \func{exit} e \func{\_exit}} \label{sec:proc_exit} -Come accennato le funzioni usate per effettuare una uscita ``normale'' da un +Come accennato le funzioni usate per effettuare un'uscita ``normale'' da un programma sono due, la prima è la funzione \func{exit} che è definita dallo -standard ANSI C; ed il cui prototipo è: +standard ANSI C ed il cui prototipo è: \begin{prototype}{stdlib.h}{void exit(int status)} Causa la conclusione ordinaria del programma restituendo il valore \var{status} al processo padre. @@ -145,7 +145,7 @@ non vengono salvati e le eventuali funzioni registrate con \func{atexit} e 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 si che ogni figlio del processo sia ereditato da \cmd{init} (vedi +stream), fa sì che ogni figlio del processo sia ereditato da \cmd{init} (vedi \secref{cha:process_handling}), manda un segnale \macro{SIGCHLD} al processo padre (vedi \secref{sec:sig_job_control}) ed infine ritorna lo stato di uscita specificato in \param{status} che può essere raccolto usando la funzione @@ -155,11 +155,11 @@ specificato in \param{status} che pu \subsection{Le funzioni \func{atexit} e \func{on\_exit}} \label{sec:proc_atexit} -Una esigenza comune che si incontra nella programmazione è quella di dover +Un'esigenza comune che si incontra nella programmazione è quella di dover effettuare una serie di operazioni di pulizia (ad esempio salvare dei dati, ripristinare dei settaggi, eliminare dei file temporanei, ecc.) prima della -conclusione di un programma. In genere queste operazioni vengono fatte in una -apposita sezione del programma, ma quando si realizza una libreria diventa +conclusione di un programma. In genere queste operazioni vengono fatte in +un'apposita sezione del programma, ma quando si realizza una libreria diventa antipatico dover richiedere una chiamata esplicita ad una funzione di pulizia al programmatore che la utilizza. @@ -182,7 +182,7 @@ funzione di pulizia da chiamare all'uscita, che non deve prendere argomenti e non deve ritornare niente (deve essere essere cioè definita come \code{void function(void)}). -Una estensione di \func{atexit} è la funzione \func{on\_exit}, che le +Un'estensione di \func{atexit} è la funzione \func{on\_exit}, che le \acr{glibc} includono per compatibilità con SunOS, ma che non è detto sia definita su altri sistemi; il suo prototipo è: \begin{prototype}{stdlib.h} @@ -253,7 +253,7 @@ esecuzione, e le varie funzioni utilizzabili per la sua gestione. Ci sono vari modi in cui i vari sistemi organizzano la memoria (ed i dettagli di basso livello dipendono spesso in maniera diretta dall'architettura dell'hardware), ma quello più tipico, usato dai sistemi unix-like come Linux è -la cosiddetta \textsl{memoria virtuale}m che consiste nell'assegnare ad ogni +la cosiddetta \textsl{memoria virtuale} che consiste nell'assegnare ad ogni processo uno spazio virtuale di indirizzamento lineare, in cui gli indirizzi vanno da zero ad un qualche valore massimo\footnote{nel caso di Linux fino al kernel 2.2 detto massimo era, per macchine a 32bit, di 2Gb, con il kernel @@ -278,12 +278,12 @@ diverse pagine di memoria virtuale appartenenti a processi diversi (come accade in genere per le pagine che contengono il codice delle librerie condivise). Ad esempio il codice della funzione \func{printf} starà su una sola pagina di memoria reale che farà da supporto a tutte le pagine di memoria -virtuale di tutti i processi hanno detta funzione nel loro codice. +virtuale di tutti i processi che hanno detta funzione nel loro codice. La corrispondenza fra le pagine della memoria virtuale e quelle della memoria fisica della macchina viene gestita in maniera trasparente dall'hardware di gestione della memoria (la \textit{Memory Management Unit} del processore). -Poiché in genere quest'ultima è solo una piccola frazione della memoria +Poiché in genere la memoria fisica è solo una piccola frazione della memoria virtuale, è necessario un meccanismo che permetta di trasferire le pagine che servono dal supporto su cui si trovano in memoria, eliminando quelle che non servono. Questo meccanismo è detto \textit{paging}, ed è uno dei compiti @@ -291,7 +291,7 @@ principali del kernel. Quando un processo cerca di accedere ad una pagina che non è nella memoria reale, avviene quello che viene chiamato un \textit{page fault}; l'hardware di -gestione della memoria genera una interruzione e passa il controllo al kernel +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. @@ -317,8 +317,8 @@ una parte di essi 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 una associazione della pagina -virtuale il kernel risponde al relativo \textit{page fault}, mandando un +scrivere da un indirizzo per il quale non esiste un'associazione della pagina +virtuale, il kernel risponde al relativo \textit{page fault} mandando un segnale \macro{SIGSEGV} al processo, che normalmente ne causa la terminazione immediata. @@ -354,15 +354,16 @@ programma C viene suddiviso nei seguenti segmenti: specificati. La seconda parte è il segmento dei dati non inizializzati, che contiene le - variabili il cui valore è stato non è assegnato esplicitamente. Ad esempio - se si definisce: + variabili il cui valore non è stato assegnato esplicitamente. Ad esempio se + si definisce: \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{} int vect[100]; \end{lstlisting} - questo valore sarà immagazzinato in questo segmento. Anch'esso viene - allocato all'avvio, e tutte le variabili vengono inizializzate a - zero (ed i puntatori a \macro{NULL}). - + questo vettore sarà immagazzinato in questo segmento. Anch'esso viene + allocato all'avvio, e tutte le variabili vengono inizializzate a zero (ed i + puntatori a \macro{NULL}).\footnote{si ricordi che questo vale solo per le + variabili che vanno nel segmento dati, e non è affatto vero in generale.} + Storicamente questo segmento viene chiamato BBS (da \textit{block started by symbol}). La sua dimensione è fissa. @@ -476,8 +477,8 @@ multipli di 8 byte. In genere su usano le funzioni \func{malloc} e \func{calloc} per allocare dinamicamente la memoria necessaria al programma, e siccome i puntatori ritornati sono di tipo generico non è necessario effettuare un cast per -assegnarli a puntatori al tipo di variabile per la quale si effettua la -allocazione. +assegnarli a puntatori al tipo di variabile per la quale si effettua +l'allocazione. La memoria allocata dinamicamente deve essere esplicitamente rilasciata usando \func{free}\footnote{le glibc provvedono anche una funzione \func{cfree} @@ -504,7 +505,7 @@ un blocco della dimensione voluta, copiandoci automaticamente il contenuto; lo spazio aggiunto non viene inizializzato. Si deve sempre avere ben presente il fatto che il blocco di memoria restituito -da \func{realloc} può non essere una estensione di quello che gli si è passato +da \func{realloc} può non essere un'estensione di quello che gli si è passato in ingresso; per questo si dovrà \emph{sempre} eseguire la riassegnazione di \var{ptr} al valore di ritorno della funzione, e reinizializzare o provvedere ad un adeguato aggiornamento di tutti gli altri puntatori all'interno del @@ -517,13 +518,13 @@ assegnare sempre a \macro{NULL} ogni puntatore liberato con \func{free}, dato che, quando il parametro è un puntatore nullo, \func{free} non esegue nessuna operazione. -Le \acr{glibc} hanno una implementazione delle routine di allocazione che è +Le \acr{glibc} hanno un'implementazione delle routine di allocazione che è controllabile dall'utente attraverso alcune variabili di ambiente, in particolare diventa possibile tracciare questo tipo di errori usando la variabile \macro{MALLOC\_CHECK\_} che quando viene definita mette in uso una -versione meno efficiente delle funzioni, che però è più tollerante nei -confronti di piccoli errori come quello di chiamate doppie a \func{free}; in -particolare: +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} @@ -539,26 +540,27 @@ non pi Un caso tipico che illustra il problema è quello in cui l'allocazione di una variabile viene fatta da una subroutine per un uso locale, ma la memoria non -viene liberata; la funzione esce e la memoria resta allocata. Chiamate -ripetute alla stessa subroutine continueranno ad allocarne ancora, causando a -lungo andare un esaurimento della memoria disponibile e l'impossibilità di -proseguire il programma. Il problema è che l'esaurimento che può avvenire in -qualunque momento, e senza nessuna relazione con la subroutine che contiene -l'errore, per questo motivo è sempre complesso trovare un \textit{memory - leak}. +viene liberata; la funzione esce e la memoria resta allocata (fino alla +terminazione del processo). Chiamate ripetute alla stessa subroutine +continueranno ad allocarne ancora, causando a lungo andare un esaurimento +della memoria disponibile e l'impossibilità di proseguire il programma. Il +problema è che l'esaurimento che può avvenire in qualunque momento, e senza +nessuna relazione con la subroutine che contiene l'errore, per questo motivo è +sempre complesso trovare un \textit{memory leak}. Per ovviare a questi problemi l'implementazione delle routine di allocazione delle \acr{glibc} mette a disposizione una serie di funzionalità (su cui torneremo in \secref{sec:xxx_advanced}) che permettono di tracciare le allocazioni e le disallocazione, e definisce anche una serie di possibili -\textsl{ganci} che permettono di sostituire alle funzioni di libreria una -propria versione (che può essere più o meno specializzata per il debugging). +\textit{hook} (\textsl{ganci}) che permettono di sostituire alle funzioni di +libreria una propria versione (che può essere più o meno specializzata per il +debugging). \subsection{La funzione \func{alloca}} \label{sec:proc_mem_alloca} -Una alternativa possibile all'uso di \func{malloc}, che non soffre dei di +Una possibile alternativa all'uso di \func{malloc}, che non soffre dei problemi di memory leak descritti in precedenza, è la funzione \func{alloca}, che invece di allocare la memoria nello heap usa il segmento di stack della funzione corrente. La sintassi è identica a quella di \func{malloc}, il suo @@ -585,7 +587,7 @@ Un altro vantaggio \func{malloc} e non viene sprecato spazio, infatti non è necessario gestire un pool di memoria da riservare e si evitano così anche i problemi di frammentazione di quest'ultimo, che comportano inefficienze sia -nella allocazione della memoria che nella esecuzione della allocazione. +nell'allocazione della memoria che nell'esecuzione dell'allocazione. Gli svantaggi sono che questa funzione non è disponibile su tutti gli Unix, e non è inserita né nello standard POSIX né in SUSv3 (ma è presente in BSD), il @@ -660,17 +662,18 @@ vuole che questo meccanismo si attivi. In generale i motivi per cui si possono avere di queste necessità sono due: \begin{itemize} \item \textsl{La velocità}. Il processo della paginazione è trasparente solo - se il programma in esecuzione se non è sensibile al tempo che occorre a - riportare la pagina in memoria; per questo motivi processi critici che hanno - esigenze di tempo reale o tolleranze critiche nella risposte (ad esempio + se il programma in esecuzione non è sensibile al tempo che occorre a + riportare la pagina in memoria; per questo motivo processi critici che hanno + esigenze di tempo reale o tolleranze critiche nelle risposte (ad esempio processi che trattano campionamenti sonori) possono non essere in grado di sopportare le variazioni della velocità di accesso dovuta alla paginazione. - + In certi casi poi un programmatore può conoscere meglio dell'algoritmo di allocazione delle pagine le esigenze specifiche del suo programma e decidere quali pagine di memoria è opportuno che restino in memoria per un aumento delle prestazioni. In genere queste sono esigenze particolari e richiedono - anche un aumento delle priorità in esecuzione (vedi \secref{sec:xxx_xxx}). + anche un aumento delle priorità in esecuzione del processo (vedi + \secref{sec:proc_real_time}). \item \textsl{La sicurezza}. Se si hanno password o chiavi segrete in chiaro in memoria queste possono essere portate su disco dal meccanismo della @@ -697,14 +700,15 @@ memoria bloccata non la sblocca. Chiaramente la terminazione del processo comporta anche la fine dell'uso della sua memoria virtuale, e quindi anche di tutti i suoi \textit{memory lock}. -I \textit{memory lock} non sono ereditati dai processi figli\footnote{ma - siccome Linux usa il copy on write gli indirizzi virtuali del figlio sono - mantenuti sullo stesso segmento di RAM del padre, quindi fintanto che un - figlio non scrive su un segmento, può usufruire dei memory lock del padre}. -Siccome la presenza di un \textit{memory lock} riduce la memoria disponibile -al sistema, con un impatto su tutti gli altri processi, solo l'amministratore -ha la capacità di bloccare una pagina. Ogni processo può però sbloccare le sue -pagine. +I \textit{memory lock} non sono ereditati dai processi figli.\footnote{ma + siccome Linux usa il \textit{copy on write} (vedi \secref{sec:proc_fork}) + gli indirizzi virtuali del figlio sono mantenuti sullo stesso segmento di + RAM del padre, quindi fintanto che un figlio non scrive su un segmento, può + usufruire del memory lock del padre.} Siccome la presenza di un +\textit{memory lock} riduce la memoria disponibile al sistema, con un impatto +su tutti gli altri processi, solo l'amministratore ha la capacità di bloccare +una pagina. Ogni processo può però sbloccare le pagine relative alla propria +memoria. Il sistema pone dei limiti all'ammontare di memoria di un processo che può essere bloccata e al totale di memoria fisica che può dedicare a questo, lo @@ -776,10 +780,16 @@ esempio limitandosi a tutte le pagine allocate a partire da un certo momento. In ogni caso un processo real-time che deve entrare in una sezione critica deve provvedere a riservare memoria sufficiente prima dell'ingresso, per -scongiurare in partenza un eventuale page fault causato dal meccanismo di copy -on write. In genere questo si fa chiamando una funzione che ha allocato una -quantità sufficiente ampia di variabili automatiche, in modo che esse vengano -mappate in RAM dallo stack, e poi ci scrive sopra. +scongiurare in partenza un eventuale page fault causato dal meccanismo di +\textit{copy on write}. Infatti se nella sezione critica si va ad utilizzare +memoria che non è ancora stata riportata in RAM si potrebbe avere un page +fault durante l'esecuzione della stessa, con conseguente rallentamento +(probabilmente inaccettabile) dei tempi di esecuzione. + +In genere si ovvia a questa problematica chiamando una funzione che ha +allocato una quantità sufficientemente ampia di variabili automatiche, in modo +che esse vengano mappate in RAM dallo stack, dopo di che, per essere sicuri +che esse siano state effettivamente portate in memoria, ci si scrive sopra. @@ -856,7 +866,7 @@ riconoscendo le possibili opzioni segnalate con \var{optstring}. Questa funzione prende come argomenti le due variabili \var{argc} e \var{argv} passate a \func{main} ed una stringa che indica quali sono le opzioni valide; la funzione effettua la scansione della lista degli argomenti ricercando ogni -stringa che comincia con \cmd{-} e ritorna ogni volta che trova una opzione +stringa che comincia con \cmd{-} e ritorna ogni volta che trova un'opzione valida. La stringa \var{optstring} indica quali sono le opzioni riconosciute ed è @@ -931,13 +941,13 @@ comando. Anzitutto si può notare che si è anzitutto (\texttt{\small 1}) disabilitata la stampa di messaggi di errore per opzioni non riconosciute, per poi passare al ciclo per la verifica delle opzioni (\texttt{\small 2-27}); per ciascuna delle -opzioni possibili si è poi provveduto ad una opportuna azione, ad esempio per +opzioni possibili si è poi provveduto ad un'azione opportuna, ad esempio per le tre opzioni che prevedono un parametro si è effettuata la decodifica del medesimo (il cui indirizzo è contenuto nella variabile \var{optarg}) avvalorando la relativa variabile (\texttt{\small 12-14}, \texttt{\small 15-17} e \texttt{\small 18-20}). Completato il ciclo troveremo in -\var{optind} l'indice in \var{argv[]} del primo degli argomenti a linea di -comando restanti. +\var{optind} l'indice in \var{argv[]} del primo degli argomenti rimanenti +nella linea di comando. Normalmente \func{getopt} compie una permutazione degli elementi di \var{argv} così che alla fine della scansione gli elementi che non sono opzioni sono @@ -1042,7 +1052,7 @@ anche altre: per una lista pi \macro{BROWSER} & $\bullet$ & $\bullet$ & $\bullet$ & Browser di default\\ \hline \end{tabular} - \caption{Variabile di ambiente più comuni definite da vari standard} + \caption{Variabili di ambiente più comuni definite da vari standard.} \label{tab:proc_env_var} \end{table} @@ -1135,7 +1145,7 @@ invece esiste il suo valore sar 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 \type{const} dal prototipo.} \func{string} alla lista delle + l'attributo \type{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 @@ -1143,13 +1153,16 @@ questa funzione una variabile automatica (per evitare i problemi esposti in 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 -\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 una allocazione fatta in -precedenza da un'altra \func{putenv}, il vettore originale (in genere piazzato -al di sopra dello stack, vedi \figref{fig:proc_mem_layout}), o la memoria -associata alle variabili di ambiente eliminate non viene comunque liberata. +\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 +\secref{sec:proc_exec}) è piazzato al di sopra dello stack, (vedi +\figref{fig:proc_mem_layout}) e non nello heap e non può essere deallocato. +Inoltre la memoria associata alle variabili di ambiente eliminate non viene +liberata. \section{Problematiche di programmazione generica} @@ -1246,7 +1259,7 @@ inoltre che l'ultimo degli argomenti fissi sia di tipo automaticamente a \type{double} ed i \type{char} e gli \type{short} ad \type{int}. Un tipo \textit{self-promoting} è un tipo che verrebbe promosso a se stesso.} il che esclude array, puntatori a funzioni e interi di tipo -\type{char} o \type{short} (con segno o meno). Una ulteriore restrizione di +\type{char} o \type{short} (con segno o meno). Un'ulteriore restrizione di alcuni compilatori è di non dichiarare l'ultimo parametro fisso come \type{register}. @@ -1321,7 +1334,7 @@ motivo \macro{va\_list} direttamente ad un altra variabile dello stesso tipo. Per risolvere questo problema lo standard ISO C99\footnote{alcuni sistemi che non hanno questa macro provvedono al suo posto \macro{\_\_va\_copy} che era il nome proposto - in una bozza dello standard} ha previsto una ulteriore macro che permette di + in una bozza dello standard} ha previsto un'ulteriore macro che permette di eseguire la copia di un puntatore alla lista degli argomenti: \begin{prototype}{stdarg.h}{void va\_copy(va\_list dest, va\_list src)} Copia l'attuale valore \param{src} del puntatore alla lista degli argomenti diff --git a/prochand.tex b/prochand.tex index c7f441d..dcad876 100644 --- a/prochand.tex +++ b/prochand.tex @@ -290,12 +290,19 @@ il processo figlio continuano ad essere eseguiti normalmente alla istruzione seguente la \func{fork}; il processo figlio è però una copia del padre, e riceve una copia dei segmenti di testo, stack e dati (vedi \secref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del -padre, ma la memoria è copiata, non condivisa,\footnote{In generale il segmento - di testo, che è identico, è condiviso e tenuto in read-only, Linux poi - utilizza la tecnica del \textit{copy-on-write}, per cui la memoria degli - altri segmenti viene copiata dal kernel per il nuovo processo solo in caso - di scrittura, rendendo molto più efficiente il meccanismo della creazione di - un nuovo processo.} pertanto padre e figlio vedono variabili diverse. +padre. Si tenga presente però che la memoria è copiata, non condivisa, pertanto +padre e figlio vedono variabili diverse. + +Per quanto riguarda la gestione della memoria in generale il segmento di +testo, che è identico, è condiviso e tenuto in read-only per il padre e per i +figli. Per gli altri segmenti Linux utilizza la tecnica del \textit{copy on + write}\index{copy on write}; questa tecnica comporta che una pagina di +memoria viene effettivamente copiata per il nuovo processo solo quando ci +viene effettuata sopra una scrittura (e si ha quindi una reale differenza fra +padre e figlio). In questo modo si rende molto più efficiente il meccanismo +della creazione di un nuovo processo, non essendo più necessaria la copia di +tutto lo spazio degli indirizzi virtuali del padre, ma solo delle pagine di +memoria che sono state modificate, e solo al momento della modifica stessa. La differenza che si ha nei due processi è che nel processo padre il valore di ritorno della funzione \func{fork} è il \acr{pid} del processo figlio, mentre @@ -1875,6 +1882,7 @@ Questa viene in genere indicata con un numero + \subsection{Il meccanismo di \textit{scheduling} standard} \label{sec:proc_sched_stand} @@ -1883,6 +1891,10 @@ possibile specificare una priorit (argomento che tratteremo più avanti) l'uso comune segue quello che è il meccanismo tradizionale con cui i sistemi +\subsection{Il meccanismo di \textit{scheduling real-time}} +\label{sec:proc_real_time} + +Per settare le