Avanti piano
[gapil.git] / prochand.tex
index 4eb3d74603609dbed04093089a5cf81e3d6bd93d..582831aa8eb6dc908ab4b8a56c526fcbb37594aa 100644 (file)
@@ -14,13 +14,12 @@ finale introdurremo alcune problematiche generiche della programmazione in
 ambiente multitasking.
 
 
-
 \section{Introduzione}
 \label{sec:proc_gen}
 
-Inizieremo con una introduzione generale ai concetti che stanno alla base
-della gestione dei processi in un sistema unix-like. Introdurremo in questa
-sezione l'architettura della gestione dei processi e le sue principali
+Inizieremo con un'introduzione generale ai concetti che stanno alla base della
+gestione dei processi in un sistema unix-like. Introdurremo in questa sezione
+l'architettura della gestione dei processi e le sue principali
 caratteristiche, dando una panoramica sull'uso delle principali funzioni di
 gestione.
 
@@ -37,9 +36,9 @@ numero unico, il cosiddetto \textit{process identifier} o, pi
 \acr{pid}.
 
 Una seconda caratteristica di un sistema Unix è che la generazione di un
-processo è unoperazione separata rispetto al lancio di un programma. In
+processo è un'operazione separata rispetto al lancio di un programma. In
 genere la sequenza è sempre quella di creare un nuovo processo, il quale
-eseguirà, in un passo successivo, il programma voluto: questo è ad esempio
+eseguirà, in un passo successivo, il programma desiderato: questo è ad esempio
 quello che fa la shell quando mette in esecuzione il programma che gli
 indichiamo nella linea di comando.
 
@@ -104,15 +103,15 @@ init-+-keventd
 
 Dato che tutti i processi attivi nel sistema sono comunque generati da
 \cmd{init} o da uno dei suoi figli\footnote{in realtà questo non è del tutto
-  vero, in Linux ci sono alcuni processi che pur comparendo come figli di
-  init, o con \acr{pid} successivi, sono in realtà generati direttamente dal
-  kernel, (come \cmd{keventd}, \cmd{kswapd}, etc.)} si possono classificare i
-processi con la relazione padre/figlio in una organizzazione gerarchica ad
-albero, in maniera analoga a come i file sono organizzati in un albero di
-directory (si veda \secref{sec:file_organization}); in \curfig\ si è mostrato
-il risultato del comando \cmd{pstree} che permette di mostrare questa
-struttura, alla cui base c'è \cmd{init} che è progenitore di tutti gli altri
-processi.
+  vero, in Linux ci sono alcuni processi speciali che pur comparendo come
+  figli di \cmd{init}, o con \acr{pid} successivi, sono in realtà generati
+  direttamente dal kernel, (come \cmd{keventd}, \cmd{kswapd}, etc.).} si
+possono classificare i processi con la relazione padre/figlio in
+un'organizzazione gerarchica ad albero, in maniera analoga a come i file sono
+organizzati in un albero di directory (si veda
+\secref{sec:file_organization}); in \curfig\ si è mostrato il risultato del
+comando \cmd{pstree} che permette di visualizzare questa struttura, alla cui
+base c'è \cmd{init} che è progenitore di tutti gli altri processi.
 
 
 Il kernel mantiene una tabella dei processi attivi, la cosiddetta
@@ -139,8 +138,9 @@ system call ed ad ogni interrupt, (ma pu
 esplicitamente). Il timer di sistema provvede comunque a che esso sia invocato
 periodicamente, generando un interrupt periodico secondo la frequenza
 specificata dalla costante \macro{HZ}, definita in \file{asm/param.h} Il
-valore usuale è 100 (è espresso in Hertz), si ha cioè un interrupt dal timer
-ogni centesimo di secondo.
+valore usuale è 100\footnote{è così per tutte le archietetture eccetto
+  l'alpha, per la quale è 1000} (è espresso in Hertz), si ha cioè un interrupt
+dal timer ogni centesimo di secondo.
 
 Ogni volta che viene eseguito, lo \textit{scheduler} effettua il calcolo delle
 priorità dei vari processi attivi (torneremo su questo in
@@ -162,7 +162,7 @@ figlio sono affrontate in dettaglio in \secref{sec:proc_fork}).
 Se si vuole che il processo padre si fermi fino alla conclusione del processo
 figlio questo deve essere specificato subito dopo la \func{fork} chiamando la
 funzione \func{wait} o la funzione \func{waitpid} (si veda
-\secref{sec:proc_wait}); queste funzioni restituiscono anche uninformazione
+\secref{sec:proc_wait}); queste funzioni restituiscono anche un'informazione
 abbastanza limitata sulle cause della terminazione del processo figlio.
 
 Quando un processo ha concluso il suo compito o ha incontrato un errore non
@@ -182,8 +182,8 @@ coi processi che 
 Il programma che un processo sta eseguendo si chiama immagine del processo (o
 \textit{process image}), le funzioni della famiglia \func{exec} permettono di
 caricare un'altro programma da disco sostituendo quest'ultimo all'immagine
-corrente; questo fa si che l'immagine precedente venga completamente
-cancellata. Questo significa che quando il nuovo programma esce anche il
+corrente; questo fa sì che l'immagine precedente venga completamente
+cancellata. Questo significa che quando il nuovo programma esce, anche il
 processo termina, e non si può tornare alla precedente immagine.
 
 Per questo motivo la \func{fork} e la \func{exec} sono funzioni molto
@@ -207,17 +207,22 @@ programmi.
 \subsection{Gli identificatori dei processi}
 \label{sec:proc_pid}
 
-Come accennato nell'introduzione ogni processo viene identificato dal sistema
+Come accennato nell'introduzione, ogni processo viene identificato dal sistema
 da un numero identificativo unico, il \textit{process id} o \acr{pid};
 quest'ultimo è un tipo di dato standard, il \type{pid\_t} che in genere è un
-intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato è \type{int}).
+intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato è
+\type{int}).
 
 Il \acr{pid} viene assegnato in forma progressiva ogni volta che un nuovo
-processo viene creato, fino ad un limite massimo (in genere essendo detto
-numero memorizzato in un intero a 16 bit si arriva a 32767) oltre il quale si
-riparte dal numero più basso disponibile\footnote{FIXME: verificare, non sono
-  sicuro}.  Per questo motivo processo il processo di avvio (\cmd{init}) ha
-sempre il \acr{pid} uguale a uno.
+processo viene creato, fino ad un limite che, essendo il \acr{pid} un numero
+positivo memorizzato in un intero a 16 bit, arriva ad un massimo di 32767.
+Oltre questo valore l'assegnazione riparte dal numero più basso disponibile a
+partire da un minimo di 300,\footnote{questi valori sono definiti dalla macro
+  \macro{PID\_MAX} in \file{threads.h} e direttamente in \file{fork.c} nei
+  sorgenti del kernel.} che serve a riservare i \acr{pid} più bassi ai processi
+eseguiti dal direttamente dal kernel.  Per questo motivo, come visto in
+\secref{sec:proc_hierarchy}, il processo di avvio (\cmd{init}) ha sempre il
+\acr{pid} uguale a uno.
 
 Tutti i processi inoltre memorizzano anche il \acr{pid} del genitore da cui
 sono stati creati, questo viene chiamato in genere \acr{ppid} (da
@@ -273,9 +278,9 @@ prototipo della funzione 
   \funcdecl{pid\_t fork(void)} 
   Crea un nuovo processo.
   
-  \bodydesc{Restituisce zero al padre e il \acr{pid} al figlio in caso di
-    successo, ritorna -1 al padre (senza creare il figlio) in caso di errore;
-    \var{errno} può assumere i valori:
+  \bodydesc{In caso di successo restituisce il \acr{pid} del figlio al padre e
+    zero al figlio; ritorna -1 al padre (senza creare il figlio) in caso di
+    errore; \var{errno} può assumere i valori:
   \begin{errlist}
   \item[\macro{EAGAIN}] non ci sono risorse sufficienti per creare un'altro
     processo (per allocare la tabella delle pagine e le strutture del task) o
@@ -286,16 +291,23 @@ prototipo della funzione 
 \end{functions}
 
 Dopo il successo dell'esecuzione di una \func{fork} sia il processo padre che
-il processo figlio continuano ad essere eseguiti normalmente allistruzione
+il processo figlio continuano ad essere eseguiti normalmente all'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
@@ -385,7 +397,7 @@ operazione che viene chiamata \textit{spawn}. Nei sistemi unix-like 
 scelto di mantenere questa separazione, dato che, come per la prima modalità
 d'uso, esistono numerosi scenari in cui si può usare una \func{fork} senza
 aver bisogno di eseguire una \func{exec}. Inoltre, anche nel caso della
-seconda modalità duso, avere le due funzioni separate permette al figlio di
+seconda modalità d'uso, avere le due funzioni separate permette al figlio di
 cambiare gli attributi del processo (maschera dei segnali, redirezione
 dell'output, \textit{user id}) prima della \func{exec}, rendendo così
 relativamente facile intervenire sulle le modalità di esecuzione del nuovo
@@ -394,11 +406,14 @@ programma.
 In \curfig\ si è riportato il corpo del codice del programma di esempio
 \cmd{forktest}, che ci permette di illustrare molte caratteristiche dell'uso
 della funzione \func{fork}. Il programma permette di creare un numero di figli
-specificato a linea di comando, e prende anche alcune opzioni per indicare
+specificato da linea di comando, e prende anche alcune opzioni per indicare
 degli eventuali tempi di attesa in secondi (eseguiti tramite la funzione
 \func{sleep}) per il padre ed il figlio (con \cmd{forktest -h} si ottiene la
 descrizione delle opzioni); il codice completo, compresa la parte che gestisce
-le opzioni a riga di comando, è disponibile nel file \file{ForkTest.c}.
+le opzioni a riga di comando, è disponibile nel file \file{ForkTest.c},
+distribuito insieme agli altri sorgenti degli esempi su
+\href{http://firenze.linux.it/~piccardi/gapil_source.tgz}
+{\texttt{http://firenze.linux.it/\~~\hspace{-2.0mm}piccardi/gapil\_source.tgz}}.
 
 Decifrato il numero di figli da creare, il ciclo principale del programma
 (\texttt{\small 24--40}) esegue in successione la creazione dei processi figli
@@ -434,12 +449,12 @@ Go to next child
 \end{verbatim} %$
 \normalsize
 
-Esaminiamo questo risultato: una prima conclusione che si può trarre è non si
-può dire quale processo fra il padre ed il figlio venga eseguito per
+Esaminiamo questo risultato: una prima conclusione che si può trarre è che non
+si può dire quale processo fra il padre ed il figlio venga eseguito per
 primo\footnote{a partire dal kernel 2.5.2-pre10 è stato introdotto il nuovo
   scheduler di Ingo Molnar che esegue sempre per primo il figlio; per
   mantenere la portabilità è opportuno non fare comunque affidamento su questo
-  comportamento} dopo la chiamata a \func{fork}; dall'esempio si può notare
+  comportamento.} dopo la chiamata a \func{fork}; dall'esempio si può notare
 infatti come nei primi due cicli sia stato eseguito per primo il padre (con la
 stampa del \acr{pid} del nuovo processo) per poi passare all'esecuzione del
 figlio (completata con i due avvisi di esecuzione ed uscita), e tornare
@@ -456,7 +471,7 @@ cui il processo padre ha eseguito pi
 figli venisse messo in esecuzione.
 
 Pertanto non si può fare nessuna assunzione sulla sequenza di esecuzione delle
-istruzioni del codice fra padre e figli, nè sull'ordine in cui questi potranno
+istruzioni del codice fra padre e figli, né sull'ordine in cui questi potranno
 essere messi in esecuzione. Se è necessaria una qualche forma di precedenza
 occorrerà provvedere ad espliciti meccanismi di sincronizzazione, pena il
 rischio di incorrere nelle cosiddette \textit{race condition} \index{race
@@ -465,9 +480,9 @@ rischio di incorrere nelle cosiddette \textit{race condition} \index{race
 Si noti inoltre che essendo i segmenti di memoria utilizzati dai singoli
 processi completamente separati, le modifiche delle variabili nei processi
 figli (come l'incremento di \var{i} in \texttt{\small 31}) sono visibili solo
-a loro, e non hanno alcun effetto sul valore che le stesse variabili hanno nel
-processo padre (ed in eventuali altri processi figli che eseguano lo stesso
-codice).
+a loro (ogni processo vede solo la propria copia della memoria), e non hanno
+alcun effetto sul valore che le stesse variabili hanno nel processo padre (ed
+in eventuali altri processi figli che eseguano lo stesso codice).
 
 Un secondo aspetto molto importante nella creazione dei processi figli è
 quello dell'interazione dei vari processi con i file; per illustrarlo meglio
@@ -591,8 +606,8 @@ comune dopo l'esecuzione di una \func{fork} 
 \item la directory di lavoro e la directory radice (vedi
   \secref{sec:file_work_dir} e \secref{sec:file_chroot}).
 \item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
-\item la maschera dei segnali bloccati e le azioni installate  (vedi
-\secref{sec:sig_xxx}).
+\item la maschera dei segnali bloccati (vedi \secref{sec:sig_sigpending}) e le
+  azioni installate (vedi \secref{sec:sig_gen_beha}).
 \item i segmenti di memoria condivisa agganciati al processo (vedi
 \secref{sec:ipc_xxx}). 
 \item i limiti sulle risorse (vedi \secref{sec:sys_xxx}).
@@ -608,7 +623,8 @@ le differenze fra padre e figlio dopo la \func{fork} invece sono:
   nel figlio sono posti a zero.
 \item i \textit{file lock} (vedi \secref{sec:file_locking}), che non
   vengono ereditati dal figlio.
-\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_xxx}), che per il figlio vengono cancellati.
+\item gli allarmi ed i segnali pendenti (vedi \secref{sec:sig_gen_beha}), che
+  per il figlio vengono cancellati.
 \end{itemize*}
 
 
@@ -667,7 +683,7 @@ eseguite alla chiusura di un processo 
 \item ad ogni processo figlio viene assegnato un nuovo padre (in genere
   \cmd{init}).
 \item viene inviato il segnale \macro{SIGCHLD} al processo padre (vedi
-  \secref{sec:sig_xxx}).
+  \secref{sec:sig_sigchld}).
 \item se il processo è un leader di sessione viene mandato un segnale di
   \macro{SIGHUP} a tutti i processi in background e il terminale di
   controllo viene disconnesso (vedi \secref{sec:sess_xxx}).
@@ -679,7 +695,7 @@ eseguite alla chiusura di un processo 
 
 Oltre queste operazioni è però necessario poter disporre di un meccanismo
 ulteriore che consenta di sapere come la terminazione è avvenuta: dato che in
-un sistema unix-like tutto viene gestito attraverso i processi il meccanismo
+un sistema unix-like tutto viene gestito attraverso i processi, il meccanismo
 scelto consiste nel riportare lo stato di terminazione (il cosiddetto
 \textit{termination status}) al processo padre.
 
@@ -707,7 +723,7 @@ terminato (si potrebbe avere cio
 
 Questa complicazione viene superata facendo in modo che il processo orfano
 venga \textsl{adottato} da \cmd{init}. Come già accennato quando un processo
-termina il kernel controlla se è il padre di altri processi in esecuzione: in
+termina, il kernel controlla se è il padre di altri processi in esecuzione: in
 caso positivo allora il \acr{ppid} di tutti questi processi viene sostituito
 con il \acr{pid} di \cmd{init} (e cioè con 1); in questo modo ogni processo
 avrà sempre un padre (nel caso possiamo parlare di un padre \textsl{adottivo})
@@ -784,7 +800,7 @@ si scrive un programma che deve essere mantenuto in esecuzione a lungo e
 creare molti figli. In questo caso si deve sempre avere cura di far leggere
 l'eventuale stato di uscita di tutti i figli (in genere questo si fa
 attraverso un apposito \textit{signal handler}, che chiama la funzione
-\func{wait}, vedi \secref{sec:sig_xxx} e \secref{sec:proc_wait}). Questa
+\func{wait}, vedi \secref{sec:sig_sigchld} e \secref{sec:proc_wait}). Questa
 operazione è necessaria perché anche se gli \textit{zombie} non consumano
 risorse di memoria o processore, occupano comunque una voce nella tabella dei
 processi, che a lungo andare potrebbe esaurirsi.
@@ -835,7 +851,7 @@ segnale termina il processo o chiama una funzione di gestione.
 processo figlio termina. Se un figlio è già terminato la funzione ritorna
 immediatamente.
 
-Al ritorno lo stato di termininazione del processo viene salvato nella
+Al ritorno lo stato di terminazione del processo viene salvato nella
 variabile puntata da \var{status} e tutte le informazioni relative al
 processo (vedi \secref{sec:proc_termination}) vengono rilasciate.  Nel
 caso un processo abbia più figli il valore di ritorno permette di
@@ -924,7 +940,7 @@ per leggerne lo stato di chiusura (ed evitare la presenza di \textit{zombie}),
 per questo la modalità più usata per chiamare queste funzioni è quella di
 utilizzarle all'interno di un \textit{signal handler} (torneremo sui segnali e
 su come gestire \macro{SIGCHLD} in \secref{sec:sig_sigwait_xxx}). In questo
-caso infatti, dato che il segnale è generato dalla terminazione un figlio,
+caso infatti, dato che il segnale è generato dalla terminazione di un figlio,
 avremo la certezza che la chiamata a \func{wait} non si bloccherà.
 
 \begin{table}[!htb]
@@ -949,9 +965,9 @@ avremo la certezza che la chiamata a \func{wait} non si bloccher
     \macro{WIFSIGNALED} ha restituito un valore non nullo.\\
     \macro{WCOREDUMP(s)}   & Vera se il processo terminato ha generato un
     file si \textit{core dump}. Può essere valutata solo se
-    \macro{WIFSIGNALED} ha restituito un valore non nullo\footnote{questa
+    \macro{WIFSIGNALED} ha restituito un valore non nullo.\footnote{questa
     macro non è definita dallo standard POSIX.1, ma è presente come estensione
-    sia in Linux che in altri unix}.\\
+    sia in Linux che in altri Unix.}\\
     \macro{WIFSTOPPED(s)}  & Vera se il processo che ha causato il ritorno di
     \func{waitpid} è bloccato. L'uso è possibile solo avendo specificato
     l'opzione \macro{WUNTRACED}. \\
@@ -978,12 +994,12 @@ anomala), uno per indicare se 
 
 Lo standard POSIX.1 definisce una serie di macro di preprocessore da usare per
 analizzare lo stato di uscita. Esse sono definite sempre in
-\file{<sys/wait.h>} ed elencate in \curtab\ (si tenga presente che queste
-macro prendono come parametro la variabile di tipo \type{int} puntata da
-\var{status}).
+\file{<sys/wait.h>} ed elencate in \tabref{tab:proc_status_macro} (si tenga
+presente che queste macro prendono come parametro la variabile di tipo
+\type{int} puntata da \var{status}).
 
 Si tenga conto che nel caso di conclusione anomala il valore restituito da
-\macro{WTERMSIG} può essere controllato contro le costanti definite in
+\macro{WTERMSIG} può essere confrontato con le costanti definite in
 \file{signal.h} ed elencate in \tabref{tab:sig_signal_list}, e stampato usando
 le apposite funzioni trattate in \secref{sec:sig_strsignal}.
 
@@ -991,7 +1007,7 @@ le apposite funzioni trattate in \secref{sec:sig_strsignal}.
 \subsection{Le funzioni \func{wait3} e \func{wait4}}
 \label{sec:proc_wait4}
 
-Linux, seguendo unestensione di BSD, supporta altre due funzioni per la
+Linux, seguendo un'estensione di BSD, supporta altre due funzioni per la
 lettura dello stato di terminazione di un processo \func{wait3} e
 \func{wait4}, analoghe alle precedenti ma che prevedono un ulteriore
 parametro attraverso il quale il kernel può restituire al padre informazioni
@@ -1156,11 +1172,12 @@ specificare il comando da eseguire; quando il parametro \var{file} non
 contiene una \file{/} esso viene considerato come un nome di programma, e
 viene eseguita automaticamente una ricerca fra i file presenti nella lista di
 directory specificate dalla variabile di ambiente \var{PATH}. Il file che
-viene posto in esecuzione è il primo che viene trovato. Se si ha un errore di
-permessi negati (cioè l'esecuzione della sottostante \func{execve} ritorna un
-\macro{EACCESS}), la ricerca viene proseguita nelle eventuali ulteriori
-directory indicate nel \var{PATH}, solo se non viene trovato nessun altro file
-viene finalmente restituito \macro{EACCESS}.
+viene posto in esecuzione è il primo che viene trovato. Se si ha un errore
+relativo a permessi di accesso insufficienti (cioè l'esecuzione della
+sottostante \func{execve} ritorna un \macro{EACCESS}), la ricerca viene
+proseguita nelle eventuali ulteriori directory indicate in \var{PATH}; solo se
+non viene trovato nessun altro file viene finalmente restituito
+\macro{EACCESS}.
 
 Le altre quattro funzioni si limitano invece a cercare di eseguire il file
 indicato dal parametro \var{path}, che viene interpretato come il
@@ -1169,7 +1186,7 @@ indicato dal parametro \var{path}, che viene interpretato come il
 \begin{figure}[htb]
   \centering
   \includegraphics[width=13cm]{img/exec_rel}
-  \caption{La interrelazione fra le sei funzioni della famiglia \func{exec}}
+  \caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.}
   \label{fig:proc_exec_relat}
 \end{figure}
 
@@ -1192,25 +1209,24 @@ la lista completa 
 \item il \textit{session id} ed il \textit{process group id} (vedi
   \secref{sec:sess_xxx}).
 \item il terminale di controllo (vedi \secref{sec:sess_xxx}).
-\item il tempo restante ad un allarme (vedi \secref{sec:sig_xxx}).
+\item il tempo restante ad un allarme (vedi \secref{sec:sig_alarm_abort}).
 \item la directory radice e la directory di lavoro corrente (vedi
   \secref{sec:file_work_dir}).
 \item la maschera di creazione dei file (\var{umask}, vedi
   \secref{sec:file_umask}) ed i \textit{lock} sui file (vedi
   \secref{sec:file_locking}).
 \item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
-  \secref{sec:sig_xxx}).
+  \secref{sec:sig_sigpending}).
 \item i limiti sulle risorse (vedi \secref{sec:sys_limits}).
 \item i valori delle variabili \var{tms\_utime}, \var{tms\_stime},
   \var{tms\_cutime}, \var{tms\_ustime} (vedi \secref{sec:xxx_xxx}).
 \end{itemize*}
 
-Oltre a questo i segnali che sono stati settati per essere ignorati nel
-processo chiamante mantengono lo stesso settaggio pure nel nuovo programma,
-tutti gli altri segnali vengono settati alla loro azione di default. Un caso
-speciale è il segnale \macro{SIGCHLD} che, quando settato a \macro{SIG\_IGN},
-può anche non essere resettato a \macro{SIG\_DFL} (si veda
-\secref{sec:sig_xxx}).
+Inoltre i segnali che sono stati settati per essere ignorati nel processo
+chiamante mantengono lo stesso settaggio pure nel nuovo programma, tutti gli
+altri segnali vengono settati alla loro azione di default. Un caso speciale è
+il segnale \macro{SIGCHLD} che, quando settato a \macro{SIG\_IGN}, può anche
+non essere resettato a \macro{SIG\_DFL} (si veda \secref{sec:sig_gen_beha}).
 
 La gestione dei file aperti dipende dal valore che ha il flag di
 \textit{close-on-exec} (trattato in \secref{sec:file_fcntl}) per ciascun file
@@ -1219,7 +1235,7 @@ restano aperti. Questo significa che il comportamento di default 
 restano aperti attraverso una \func{exec}, a meno di una chiamata esplicita a
 \func{fcntl} che setti il suddetto flag.
 
-Per le directory lo standard POSIX.1 richiede che esse vengano chiuse
+Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse
 attraverso una \func{exec}, in genere questo è fatto dalla funzione
 \func{opendir} (vedi \secref{sec:file_dir_read}) che effettua da sola il
 settaggio del flag di \textit{close-on-exec} sulle directory che apre, in
@@ -1271,7 +1287,7 @@ problematiche connesse ad una gestione accorta dei privilegi.
 Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in
   realtà già esistono estensioni di questo modello base, che lo rendono più
   flessibile e controllabile, come le \textit{capabilities}, le ACL per i file
-  o il \textit{Mandatory Access Control} di SELinux} di sicurezza di un
+  o il \textit{Mandatory Access Control} di SELinux.} di sicurezza di un
 sistema unix-like è fondato sui concetti di utente e gruppo, e sulla
 separazione fra l'amministratore (\textsl{root}, detto spesso anche
 \textit{superuser}) che non è sottoposto a restrizioni, ed il resto degli
@@ -1348,13 +1364,13 @@ identificatori ai valori corrispondenti all'utente che entra nel sistema.
 
 Al secondo gruppo appartengono l'\textit{effective user id} e
 l'\textit{effective group id} (a cui si aggiungono gli eventuali
-\textit{supplementary group id} dei gruppi dei quale l'utente fa parte).
+\textit{supplementary group id} dei gruppi dei quali l'utente fa parte).
 Questi sono invece gli identificatori usati nella verifiche dei permessi del
 processo e per il controllo di accesso ai file (argomento affrontato in
 dettaglio in \secref{sec:file_perm_overview}). 
 
 Questi identificatori normalmente sono identici ai corrispondenti del gruppo
-\textsl{reale} tranne nel caso in cui, come accennato in
+\textit{real} tranne nel caso in cui, come accennato in
 \secref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
 \acr{suid} o \acr{sgid} settati (il significato di questi bit è affrontato in
 dettaglio in \secref{sec:file_suid_sgid}). In questo caso essi saranno settati
@@ -1393,10 +1409,10 @@ servano di nuovo.
 Questo in Linux viene fatto usando altri due gruppi di identificatori, il
 \textit{saved} ed il \textit{filesystem}, analoghi ai precedenti. Il primo
 gruppo è lo stesso usato in SVr4, e previsto dallo standard POSIX quando è
-definita la costante \macro{\_POSIX\_SAVED\_IDS}\footnote{in caso si abbia a
+definita la costante \macro{\_POSIX\_SAVED\_IDS},\footnote{in caso si abbia a
   cuore la portabilità del programma su altri Unix è buona norma controllare
   sempre la disponibilità di queste funzioni controllando se questa costante è
-  definita}, il secondo gruppo è specifico di Linux e viene usato per
+  definita.} il secondo gruppo è specifico di Linux e viene usato per
 migliorare la sicurezza con NFS.
 
 Il \textit{saved user id} e il \textit{saved group id} sono copie
@@ -1465,7 +1481,7 @@ riportare l'\textit{effective user id} a quello dell'utente che ha lanciato il
 programma, effettuare il lavoro che non necessita di privilegi aggiuntivi, ed
 eventualmente tornare indietro.
 
-Come esempio per chiarire dell'uso di queste funzioni prendiamo quello con cui
+Come esempio per chiarire l'uso di queste funzioni prendiamo quello con cui
 viene gestito l'accesso al file \file{/var/log/utmp}.  In questo file viene
 registrato chi sta usando il sistema al momento corrente; chiaramente non può
 essere lasciato aperto in scrittura a qualunque utente, che potrebbe
@@ -1476,7 +1492,7 @@ esempio tutti i programmi di terminale in X, o il programma \cmd{screen} che
 crea terminali multipli su una console) appartengono a questo gruppo ed hanno
 il bit \acr{sgid} settato.
 
-Quando uno di questi programmi (ad esempio \cmd{xterm}) viene lanciato la
+Quando uno di questi programmi (ad esempio \cmd{xterm}) viene lanciato, la
 situazione degli identificatori è la seguente:
 \begin{eqnarray*}
   \label{eq:1}
@@ -1485,7 +1501,7 @@ situazione degli identificatori 
   \textit{saved group id}     &=& \textrm{\acr{utmp}}
 \end{eqnarray*}
 in questo modo, dato che l'\textit{effective group id} è quello giusto, il
-programma può accedere a \file{/var/log/utmp} in scrittura ed aggiornarlo, a
+programma può accedere a \file{/var/log/utmp} in scrittura ed aggiornarlo. A
 questo punto il programma può eseguire una \code{setgid(getgid())} per settare
 l'\textit{effective group id} a quello dell'utente (e dato che il \textit{real
   group id} corrisponde la funzione avrà successo), in questo modo non sarà
@@ -1501,9 +1517,9 @@ e ogni processo lanciato dal terminale avrebbe comunque \acr{gid} come
 \textit{effective group id}. All'uscita dal terminale, per poter di nuovo
 aggiornare lo stato di \file{/var/log/utmp} il programma eseguirà una
 \code{setgid(utmp)} (dove \var{utmp} è il valore numerico associato al gruppo
-\acr{utmp}, ottenuto ad esempio con una \func{getegid}), dato che in questo
-caso il valore richiesto corrisponde al \textit{saved group id} la funzione
-avrà successo e riporterà la situazione a:
+\acr{utmp}, ottenuto ad esempio con una precedente \func{getegid}), dato che
+in questo caso il valore richiesto corrisponde al \textit{saved group id} la
+funzione avrà successo e riporterà la situazione a:
 \begin{eqnarray*}
   \label{eq:3}
   \textit{real group id}      &=& \textrm{\acr{gid} (invariato)}  \\
@@ -1572,7 +1588,7 @@ Lo stesso problema di propagazione dei privilegi ad eventuali processi figli
 si porrebbe per i \textit{saved id}: queste funzioni derivano da
 un'implementazione che non ne prevede la presenza, e quindi non è possibile
 usarle per correggere la situazione come nel caso precedente. Per questo
-motivo in Linux tutte le volte che vengono usata per modificare uno degli
+motivo in Linux tutte le volte che vengono usate per modificare uno degli
 identificatori ad un valore diverso dal \textit{real id} precedente, il
 \textit{saved id} viene sempre settato al valore dell'\textit{effective id}.
 
@@ -1608,7 +1624,7 @@ il settaggio di tutti gli identificatori.
 \subsection{Le funzioni \func{setresuid} e \func{setresgid}}
 \label{sec:proc_setresuid}
 
-Queste due funzioni sono unestensione introdotta in Linux dal kernel 2.1.44,
+Queste due funzioni sono un'estensione introdotta in Linux dal kernel 2.1.44,
 e permettono un completo controllo su tutti gli identificatori (\textit{real},
 \textit{effective} e \textit{saved}), i prototipi sono:
 \begin{functions}
@@ -1655,7 +1671,7 @@ prototipi sono:
   variabili di ritorno non sono validi.}
 \end{functions}
 
-Anche queste funzioni sono unestensione specifica di Linux, e non richiedono
+Anche queste funzioni sono un'estensione specifica di Linux, e non richiedono
 nessun privilegio. I valori sono restituiti negli argomenti, che vanno
 specificati come puntatori (è un'altro esempio di \textit{value result
   argument}). Si noti che queste funzioni sono le uniche in grado di leggere i
@@ -1707,11 +1723,10 @@ coincide con uno dei \textit{real}, \textit{effective} o \textit{saved id}.
 \subsection{Le funzioni \func{setgroups} e \func{getgroups}}
 \label{sec:proc_setgroups}
 
-Le ultime funzioni che esamineremo sono quelle sono quelle che permettono di
-operare sui gruppi supplementari. Ogni processo può avere fino a
-\macro{NGROUPS\_MAX} gruppi supplementari in aggiunta al gruppo primario,
-questi vengono ereditati dal processo padre e possono essere cambiati con
-queste funzioni.
+Le ultime funzioni che esamineremo sono quelle che permettono di operare sui
+gruppi supplementari. Ogni processo può avere fino a \macro{NGROUPS\_MAX}
+gruppi supplementari in aggiunta al gruppo primario, questi vengono ereditati
+dal processo padre e possono essere cambiati con queste funzioni.
 
 La funzione che permette di leggere i gruppi supplementari è \func{getgroups};
 questa funzione è definita nello standard POSIX ed il suo prototipo è:
@@ -1752,8 +1767,8 @@ ottenere tutti i gruppi a cui appartiene un utente; il suo prototipo 
 \noindent la funzione esegue una scansione del database dei gruppi (si veda
 \secref{sec:sys_user_group}) e ritorna in \param{groups} la lista di quelli a
 cui l'utente appartiene. Si noti che \param{ngroups} è passato come puntatore
-perché qualora il valore specificato sia troppo piccolo la funzione ritorna -1
-e passando indietro il numero dei gruppi trovati.
+perché qualora il valore specificato sia troppo piccolo la funzione ritorna
+-1, passando indietro il numero dei gruppi trovati.
 
 Per settare i gruppi supplementari di un processo ci sono due funzioni, che
 possono essere usate solo se si hanno i privilegi di amministratore. La prima
@@ -1776,7 +1791,7 @@ delle due 
 \end{functions}
 
 Se invece si vogliono settare i gruppi supplementari del processo a quelli di
-un utente specifico si può usare \func{initgroups} il cui prototipo è:
+un utente specifico, si può usare \func{initgroups} il cui prototipo è:
 \begin{functions}
   \headdecl{sys/types.h}
   \headdecl{grp.h}
@@ -1792,9 +1807,9 @@ un utente specifico si pu
 \end{functions}
 
 La funzione esegue la scansione del database dei gruppi (usualmente
-\file{/etc/groups}) cercando i gruppi di cui è membro \param{user} costruendo
-una lista di gruppi supplementari a cui aggiunge \param{group}, che poi setta
-usando \func{setgroups}.
+\file{/etc/groups}) cercando i gruppi di cui è membro \param{user} e
+costruendo una lista di gruppi supplementari a cui aggiunge \param{group}, che
+poi setta usando \func{setgroups}.
 
 Si tenga presente che sia \func{setgroups} che \func{initgroups} non sono
 definite nello standard POSIX.1 e che pertanto non è possibile utilizzarle
@@ -1806,9 +1821,116 @@ quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag
 \label{sec:proc_priority}
 
 In questa sezione tratteremo più approfonditamente i meccanismi con il quale
-lo \textit{scheduler} assegna la CPU ai vari processi attivi, illustrando le
-varie funzioni che permettono di leggere e modificare le priorità di
-esecuzione dei programmi.
+lo \textit{scheduler}\footnote{che è la parte del kernel che si occupa di
+  stabilire quale processo dovrà essere posto in esecuzione.} assegna la CPU
+ai vari processi attivi. In particolare prenderemo in esame i vari meccanismi
+con cui viene gestita l'assegnazione del tempo di CPU, ed illustreremo le
+varie funzioni di gestione.
+
+
+\subsection{I meccanismi di \textit{scheduling}}
+\label{sec:proc_sched}
+
+La scelta di un meccanismo che sia in grado di distribuire in maniera efficace
+il tempo di CPU per l'esecuzione dei processi è sempre una questione delicata,
+ed oggetto di numerose ricerche; in ogni caso essa dipende in maniera
+essenziale anche dal tipo di utilizzo che deve essere fatto del sistema.
+
+La cosa è resa ancora più complicata dal fatto che con le architetture
+multi-processore si introduce anche la problematica dovuta alla scelta di
+quale sia la CPU più opportuna da utilizzare.\footnote{nei processori moderni
+  la presenza di ampie cache può rendere poco efficiente trasferire
+  l'esecuzione di un processo da una CPU ad un'altra, per cui occorrono
+  meccanismi per determinare quale è la migliore scelta fra le diverse CPU.}
+Tutto questo comunque appartiene alle sottigliezze dell'implementazione del
+kernel, e dal punto di vista dei programmi che girano in user space, anche
+quando si hanno più processori (e dei processi che sono eseguiti davvero in
+contemporanea), si può pensare alle politiche di scheduling come concernenti
+la risorsa \textsl{tempo di esecuzione}, la cui assegnazione sarà governata
+dagli stessi meccanismi di scelta di priorità, solo che nel caso di più
+processori sarà a disposizione di più di un processo alla volta.
+
+Si tenga presente inoltre che l'utilizzo della CPU è soltanto una delle
+risorse (insieme alla memoria e all'accesso alle periferiche) che sono
+necessarie per l'esecuzione di un programma, e spesso non è neanche la più
+importante. Per questo non è affatto detto che dare ad un programma la massima
+priorità di esecuzione abbia risultati significativi in termini di
+prestazioni.
+
+Il meccanismo tradizionale di scheduling di Unix (che tratteremo in
+\secref{sec:proc_sched_stand}) è sempre stato basato su delle \textsl{priorità
+  dinamiche}, in modo da assicurare che tutti i processi, anche i meno
+importanti, possano ricevere un po' di tempo di CPU. In sostanza quando un
+processo ottiene la CPU la sua priorità viene diminuita. In questo modo alla
+fine, anche un processo con priorità iniziale molto bassa, finisce per avere
+una priorità sufficiente per essere eseguito.
+
+Lo standard POSIX.1b però ha introdotto il concetto di \textsl{priorità
+  assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione
+alla normale priorità dinamica), per tenere conto dei sistemi
+real-time,\footnote{per sistema real-time si intende un sistema in grado di
+  eseguire operazioni in tempo reale; in genere si tende a distinguere fra
+  l'\textit{hard real-time} in cui è necessario che i tempi di esecuzione di
+  un programma siano determinabili con certezza assoluta, come nel caso di
+  meccanismi di controllo di macchine, dove uno sforamento dei tempi avrebbe
+  conseguenze disastrose, e \textit{soft-real-time} in cui un occasionale
+  sforamento è ritenuto accettabile.} in cui è vitale che i processi che
+devono essere eseguiti in un determinato momento non debbano aspettare la
+conclusione di altri che non hanno questa necessità.
+
+Il concetto di priorità assoluta dice che quando due processi si contendono
+l'esecuzione, vince sempre quello con la priorità assoluta più alta, anche
+quando l'altro è in esecuzione (grazie al \textit{prehemptive scheduling}).
+Ovviamente questo avviene solo per i processi che sono pronti per essere
+eseguiti (cioè nello stato \textit{runnable},\footnote{lo stato di un processo
+  è riportato nel campo \texttt{STAT} dell'output del comando \cmd{ps},
+  abbiamo già visto che lo stato di \textit{zombie} è indicato con \texttt{Z},
+  gli stati \textit{runnable}, \textit{sleep} e di I/O (\textit{uninteruttible
+    sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.})
+la priorità assoluta viene invece ignorata per quelli che sono bloccati su una
+richiesta di I/O o in stato di \textit{sleep}.  La priorità assoluta viene in
+genere indicata con un numero intero, ed un valore più alto comporta una
+priorità maggiore, su questa politica di scheduling torneremo in
+\secref{sec:proc_real_time}.  
+
+In generale quello che succede in tutti gli Unix moderni è che ai processi
+normali viene sempre data una priorità assoluta pari a zero, e la decisione di
+assegnazione della CPU è fatta solo in base ad una priorità dinamica che è
+calcolata indipendentemente. È tuttavia possibile assegnare anche una priorità
+assoluta nel qual caso un processo avrà la precedenza su tutti gli altri di
+priorità inferiore che saranno eseguiti solo quando quest'ultimo non avrà
+bisogno della CPU.
+
+
+\subsection{Il meccanismo di \textit{scheduling} standard}
+\label{sec:proc_sched_stand}
+
+A meno che non si abbiano specifiche esigenze, l'unico meccanismo di
+scheduling con il quale si avrà a che fare è quello tradizionale che prevede
+solo priorità dinamiche, ed è di questo che di norma ci si dovrà preoccupare
+nella programmazione.
+
+Come accennato in Linux tutti i processi ordinari hanno la stessa priorità
+assoluta. Quello che determina quale, fra tutti i processi in attesa di
+esecuzione, sarà eseguito per primo, è la priorità dinamica, che è chiamata
+così proprio perché viene varia nel corso dell'esecuzione di un processo.
+
+
+
+
+\subsection{Il meccanismo di \textit{scheduling real-time}}
+\label{sec:proc_real_time}
+
+Per settare le 
+
+
+\footnote{a meno che non si siano installate le patch di RTLinux o RTAI, con i
+  quali è possibile ottenere un sistema effettivamente hard real-time.}
+
+in realtà non si tratta di un vero hard real-time, in quanto
+  la presenza di eventuali interrupt o di page fault può sempre interrompere
+  l'esecuzione di un processo, a meno di non installare le estensioni di
+  RTLinux o RTAI, il normale kernel non è real-time.
 
 
 
@@ -1833,7 +1955,7 @@ abbiamo affrontato la gestione dei processi.
 \label{sec:proc_atom_oper}
 
 La nozione di \textsl{operazione atomica} deriva dal significato greco della
-parola atomo, cioè indivisibile; si dice infatti che unoperazione è atomica
+parola atomo, cioè indivisibile; si dice infatti che un'operazione è atomica
 quando si ha la certezza che, qualora essa venga effettuata, tutti i passaggi
 che devono essere compiuti per realizzarla verranno eseguiti senza possibilità
 di interruzione in una fase intermedia.
@@ -1858,7 +1980,7 @@ processi.
 Nel caso dei segnali invece la situazione è molto più delicata, in quanto lo
 stesso processo, e pure alcune system call, possono essere interrotti in
 qualunque momento, e le operazioni di un eventuale \textit{signal handler}
-sono compiute nello stesso spazio di indirizzi del processo. Per questo anche
+sono compiute nello stesso spazio di indirizzi del processo. Per questo, anche
 il solo accesso o l'assegnazione di una variabile possono non essere più
 operazioni atomiche (torneremo su questi aspetti in \secref{sec:sign_xxx}).
 
@@ -1879,7 +2001,7 @@ condiviso, onde evitare problemi con le ottimizzazioni del codice.
 Si definiscono \textit{race condition} tutte quelle situazioni in cui processi
 diversi operano su una risorsa comune, ed in cui il risultato viene a
 dipendere dall'ordine in cui essi effettuano le loro operazioni. Il caso
-tipico è quello di unoperazione che viene eseguita da un processo in più
+tipico è quello di un'operazione che viene eseguita da un processo in più
 passi, e può essere compromessa dall'intervento di un altro processo che
 accede alla stessa risorsa quando ancora non tutti i passi sono stati
 completati.
@@ -1926,26 +2048,26 @@ eseguire in maniera atomica le operazioni necessarie.
 
 Si dice \textsl{rientrante} una funzione che può essere interrotta in
 qualunque punto della sua esecuzione ed essere chiamata una seconda volta da
-un altro thread di esecuzione senza che questo comporti nessun problema nella
-esecuzione della stessa. La problematica è comune nella programmazione
+un altro thread di esecuzione senza che questo comporti nessun problema
+nell'esecuzione della stessa. La problematica è comune nella programmazione
 multi-thread, ma si hanno gli stessi problemi quando si vogliono chiamare
 delle funzioni all'interno dei manipolatori dei segnali.
 
 Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
-queste infatti vengono tutte le volte allocate nello stack, e un'altra
-invocazione non fa altro che allocarne un'altra copia. Una funzione può non
-essere rientrante quando opera su memoria che non è nello stack.  Ad esempio
-una funzione non è mai rientrante se usa una variabile globale o statica.
-
-Nel caso invece la funzione operi su un oggetto allocato dinamicamente la cosa
-viene a dipendere da come avvengono le operazioni; se l'oggetto è creato ogni
-volta e ritornato indietro la funzione può essere rientrante, se invece esso
-viene individuato dalla funzione stessa due chiamate alla stessa funzione
-potranno interferire quando entrambe faranno riferimento allo stesso oggetto.
-Allo stesso modo una funzione può non essere rientrante se usa e modifica un
-oggetto che le viene fornito dal chiamante: due chiamate possono interferire
-se viene passato lo stesso oggetto; in tutti questi casi occorre molta cura da
-parte del programmatore.
+queste infatti vengono allocate nello stack, e un'altra invocazione non fa
+altro che allocarne un'altra copia. Una funzione può non essere rientrante
+quando opera su memoria che non è nello stack.  Ad esempio una funzione non è
+mai rientrante se usa una variabile globale o statica.
+
+Nel caso invece la funzione operi su un oggetto allocato dinamicamente, la
+cosa viene a dipendere da come avvengono le operazioni: se l'oggetto è creato
+ogni volta e ritornato indietro la funzione può essere rientrante, se invece
+esso viene individuato dalla funzione stessa, due chiamate alla stessa
+funzione potranno interferire quando entrambe faranno riferimento allo stesso
+oggetto.  Allo stesso modo una funzione può non essere rientrante se usa e
+modifica un oggetto che le viene fornito dal chiamante: due chiamate possono
+interferire se viene passato lo stesso oggetto; in tutti questi casi occorre
+molta cura da parte del programmatore.
 
 In genere le funzioni di libreria non sono rientranti, molte di esse ad
 esempio utilizzano variabili statiche, le \acr{glibc} però mettono a