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.
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.
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.
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
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
\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.
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;
\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
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.
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:
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
\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
\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
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
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.
\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.
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
\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.
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}
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
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
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.
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.
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.
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}
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
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}
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
\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
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
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
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.
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 è
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
\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}
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
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}
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}.
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