Varie correzioni da Fabio Rossi, e relative aggiunte nei ringrazimenti per
[gapil.git] / prochand.tex
index 07ebb358579f5375876cce2416e9ea9a80554bfc..651e14536584e9e1e5289714ea92da1ef8cdc928 100644 (file)
@@ -1,39 +1,55 @@
+%% prochand.tex
+%%
+%% Copyright (C) 2000-2005 Simone Piccardi.  Permission is granted to
+%% copy, distribute and/or modify this document under the terms of the GNU Free
+%% Documentation License, Version 1.1 or any later version published by the
+%% Free Software Foundation; with the Invariant Sections being "Un preambolo",
+%% with no Front-Cover Texts, and with no Back-Cover Texts.  A copy of the
+%% license is included in the section entitled "GNU Free Documentation
+%% License".
+%%
 \chapter{La gestione dei processi}
 \label{cha:process_handling}
 
-Come accennato nell'introduzione in un sistema unix ogni attività del sistema
-viene svolta tramite i processi.  In sostanza i processi costituiscono l'unità
-base per l'allocazione e l'uso delle risorse del sistema.
+Come accennato nell'introduzione in un sistema Unix tutte le operazioni
+vengono svolte tramite opportuni processi.  In sostanza questi ultimi vengono
+a costituire l'unità base per l'allocazione e l'uso delle risorse del sistema.
 
-Nel precedente capitolo abbiamo visto come funziona un singolo processo, in
-questo capitolo affronteremo i dettagli della creazione e della distruzione
-dei processi, della gestione dei loro attributi e privilegi, e di tutte le
-funzioni a questo connesse.
+Nel precedente capitolo abbiamo esaminato il funzionamento di un processo come
+unità a se stante, in questo esamineremo il funzionamento dei processi
+all'interno del sistema. Saranno cioè affrontati i dettagli della creazione e
+della terminazione dei processi, della gestione dei loro attributi e
+privilegi, e di tutte le funzioni a questo connesse. Infine nella sezione
+finale introdurremo alcune problematiche generiche della programmazione in
+ambiente multitasking.
 
 
 \section{Introduzione}
 \label{sec:proc_gen}
 
-Partiremo con una introduzione generale ai concetti che stanno alla base della
-gestione dei processi in unix. Introdurremo in questa sezione l'architettura
-della gestione dei processi e le sue principali caratteristiche, e daremo una
-panoramica sull'uso delle principali funzioni per la gestione dei processi.
+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.
 
-\subsection{La gerarchia dei processi}
+
+\subsection{L'architettura della gestione dei processi}
 \label{sec:proc_hierarchy}
 
 A differenza di quanto avviene in altri sistemi (ad esempio nel VMS la
 generazione di nuovi processi è un'operazione privilegiata) una delle
-caratteristiche di unix (che esamineremo in dettaglio più avanti) è che
+caratteristiche di Unix (che esamineremo in dettaglio più avanti) è che
 qualunque processo può a sua volta generarne altri, detti processi figli
 (\textit{child process}). Ogni processo è identificato presso il sistema da un
-numero unico, il cosiddetto \textit{process identifier} o, più brevemente, 
-\acr{pid}.
+numero univoco, il cosiddetto \textit{process identifier} o, più brevemente,
+\acr{pid}, assegnato in forma progressiva (vedi sez.~\ref{sec:proc_pid}) quando
+il processo viene creato.
 
-Una seconda caratteristica di un sistema unix è che la generazione di un
-processo è unoperazione separata rispetto al lancio di un programma. In
+Una seconda caratteristica di un sistema Unix è che la generazione di un
+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.
 
@@ -49,7 +65,7 @@ Ovviamente \cmd{init} 
 partire tutti gli altri processi necessari al funzionamento del sistema,
 inoltre \cmd{init} è essenziale per svolgere una serie di compiti
 amministrativi nelle operazioni ordinarie del sistema (torneremo su alcuni di
-essi in \secref{sec:proc_termination}) e non può mai essere terminato. La
+essi in sez.~\ref{sec:proc_termination}) e non può mai essere terminato. La
 struttura del sistema comunque consente di lanciare al posto di \cmd{init}
 qualunque altro programma, e in casi di emergenza (ad esempio se il file di
 \cmd{init} si fosse corrotto) è ad esempio possibile lanciare una shell al suo
@@ -98,37 +114,74 @@ 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_file_struct}); 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}, ecc.).} 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
+sez.~\ref{sec:file_organization}); in fig.~\ref{fig:proc_tree} 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
+\textit{process table}; per ciascun processo viene mantenuta una voce,
+costituita da una struttura \struct{task\_struct}, nella tabella dei processi
+che contiene tutte le informazioni rilevanti per quel processo. Tutte le
+strutture usate a questo scopo sono dichiarate nell'header file
+\file{linux/sched.h}, ed uno schema semplificato, che riporta la struttura
+delle principali informazioni contenute nella \struct{task\_struct} (che in
+seguito incontreremo a più riprese), è mostrato in
+fig.~\ref{fig:proc_task_struct}.
+
+\begin{figure}[htb]
+  \centering
+  \includegraphics[width=13cm]{img/task_struct}
+  \caption{Schema semplificato dell'architettura delle strutture usate dal
+    kernel nella gestione dei processi.}
+  \label{fig:proc_task_struct}
+\end{figure}
 
-\subsection{Una panoramica sulle funzioni di gestione}
+Come accennato in sez.~\ref{sec:intro_unix_struct} è lo
+\textit{scheduler}\index{\textit{scheduler}} che decide quale processo mettere
+in esecuzione; esso viene eseguito ad ogni system call ed ad ogni
+interrupt,\footnote{più in una serie di altre occasioni. NDT completare questa
+  parte.} (ma può essere anche attivato esplicitamente). Il timer di sistema
+provvede comunque a che esso sia invocato periodicamente, generando un
+interrupt periodico secondo la frequenza specificata dalla costante
+\const{HZ}, definita in \file{asm/param.h}, ed il cui valore è espresso in
+Hertz.\footnote{Il valore usuale di questa costante è 100, per tutte le
+  architetture eccetto l'alpha, per la quale è 1000. Occorre fare attenzione a
+  non confondere questo valore con quello dei clock tick (vedi
+  sez.~\ref{sec:sys_unix_time}).}
+%Si ha cioè un interrupt dal timer ogni centesimo di secondo.
+
+Ogni volta che viene eseguito, lo \textit{scheduler}\index{\textit{scheduler}}
+effettua il calcolo delle priorità dei vari processi attivi (torneremo su
+questo in sez.~\ref{sec:proc_priority}) e stabilisce quale di essi debba
+essere posto in esecuzione fino alla successiva invocazione.
+
+
+\subsection{Una panoramica sulle funzioni fondamentali}
 \label{sec:proc_handling_intro}
 
-I processi vengono creati dalla funzione \func{fork}; in molti unix questa è
-una system call, Linux però usa un'altra nomenclatura, e la funzione fork è
-basata a sua volta sulla system call \func{\_\_clone}, che viene usata anche
-per generare i \textit{thread}.  Il processo figlio creato dalla \func{fork} è
-una copia identica del processo processo padre, ma ha nuovo \acr{pid} e viene
+In un sistema unix-like i processi vengono sempre creati da altri processi
+tramite la funzione \func{fork}; il nuovo processo (che viene chiamato
+\textsl{figlio}) creato dalla \func{fork} è una copia identica del processo
+processo originale (detto \textsl{padre}), ma ha un nuovo \acr{pid} e viene
 eseguito in maniera indipendente (le differenze fra padre e figlio sono
-affrontate in dettaglio in \secref{sec:proc_fork}).
+affrontate in dettaglio in sez.~\ref{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 una informazione
-abbastanza limitata (lo stato di terminazione) sulle cause della terminazione
-del processo.
+sez.~\ref{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
 risolvibile esso può essere terminato con la funzione \func{exit} (si veda
-quanto discusso in \secref{sec:proc_conclusion}). La vita del processo però
+quanto discusso in sez.~\ref{sec:proc_conclusion}). La vita del processo però
 termina solo quando la notifica della sua conclusione viene ricevuta dal
 processo padre, a quel punto tutte le risorse allocate nel sistema ad esso
 associate vengono rilasciate.
@@ -142,9 +195,9 @@ 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
+caricare un altro programma da disco sostituendo quest'ultimo all'immagine
+corrente; questo fa sì che l'immagine precedente venga completamente
+cancellata. Questo significa che quando il nuovo programma termina, 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
@@ -154,172 +207,153 @@ non ritorna mai (in quanto con essa viene eseguito un altro programma).
 
 
 
-\section{La gestione dei processi}
+\section{Le funzioni di base}% della gestione dei processi}
 \label{sec:proc_handling}
 
-In questa sezione tratteremo le funzioni per la gestione dei processi, a
-partire dalle funzioni elementari che permettono di leggerne gli
-identificatori, alle varie funzioni di manipolazione dei processi, che
-riguardano la loro creazione, terminazione, e la messa in esecuzione di altri
+In questa sezione tratteremo le problematiche della gestione dei processi
+all'interno del sistema, illustrandone tutti i dettagli.  Inizieremo con le
+funzioni elementari che permettono di leggerne gli identificatori, per poi
+passare alla spiegazione delle funzioni base che si usano per la creazione e
+la terminazione dei processi, e per la messa in esecuzione degli altri
 programmi.
 
 
 \subsection{Gli identificatori dei processi}
 \label{sec:proc_pid}
 
-Come accennato nell'introduzione ogni processo viene identificato dal sistema
-da un numero identificativo unico, il \textit{process id} o \acr{pid};
+Come accennato nell'introduzione, ogni processo viene identificato dal sistema
+da un numero identificativo univoco, 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 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 (FIXME: verificare, non sono sicuro).
-Per questo motivo processo il processo di avvio (\cmd{init}) ha sempre il
-\acr{pid} uguale a uno. 
+intero con segno (nel caso di Linux e delle \acr{glibc} il tipo usato è
+\ctyp{int}).
+
+Il \acr{pid} viene assegnato in forma progressiva\footnote{in genere viene
+  assegnato il numero successivo a quello usato per l'ultimo processo creato,
+  a meno che questo numero non sia già utilizzato per un altro \acr{pid},
+  \acr{pgid} o \acr{sid} (vedi sez.~\ref{sec:sess_proc_group}).} ogni volta
+che un nuovo 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 32768.  Oltre questo valore l'assegnazione riparte dal numero più
+basso disponibile a partire da un minimo di 300,\footnote{questi valori, fino
+  al kernel 2.4.x, sono definiti dalla macro \const{PID\_MAX} in
+  \file{threads.h} e direttamente in \file{fork.c}, con il kernel 2.5.x e la
+  nuova interfaccia per i thread creata da Ingo Molnar anche il meccanismo di
+  allocazione dei \acr{pid} è stato modificato.} che serve a riservare i
+\acr{pid} più bassi ai processi eseguiti direttamente dal kernel.  Per questo
+motivo, come visto in sez.~\ref{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
-\textit{parent process id}).  Questi due identificativi possono essere
-ottenuti da programma usando le funzioni:
-
+\textit{parent process ID}).  Questi due identificativi possono essere
+ottenuti usando le due funzioni \funcd{getpid} e \funcd{getppid}, i cui
+prototipi sono:
 \begin{functions}
-\headdecl{sys/types.h}
-\headdecl{unistd.h}
-\funcdecl{pid\_t getpid(void)} restituisce il pid del processo corrente.
-\funcdecl{pid\_t getppid(void)} restituisce il pid del padre del processo
-    corrente.
+  \headdecl{sys/types.h} 
+  \headdecl{unistd.h} 
+  \funcdecl{pid\_t getpid(void)}
+  
+  Restituisce il \acr{pid} del processo corrente.  
+  
+  \funcdecl{pid\_t getppid(void)} 
+  
+  Restituisce il \acr{pid} del padre del processo corrente.
 
-Entrambe le funzioni non riportano condizioni di errore. 
+\bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
 \end{functions}
-esempi dell'uso di queste funzioni sono riportati in
-\figref{fig:proc_fork_code}, nel programma di esempio \file{ForkTest.c}.
+\noindent esempi dell'uso di queste funzioni sono riportati in
+fig.~\ref{fig:proc_fork_code}, nel programma \file{ForkTest.c}.
 
-Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende il
-candidato ideale per generare ulteriori indicatori associati al processo di
-cui diventa possibile garantire l'unicità: ad esempio la funzione
-\func{tmpname} (si veda \secref{sec:file_temp_file}) usa il \acr{pid} per
-generare un pathname univoco, che non potrà essere replicato da un'altro
-processo che usi la stessa funzione. 
+Il fatto che il \acr{pid} sia un numero univoco per il sistema lo rende un
+candidato per generare ulteriori indicatori associati al processo di cui
+diventa possibile garantire l'unicità: ad esempio in alcune implementazioni la
+funzione \func{tempnam} (si veda sez.~\ref{sec:file_temp_file}) usa il
+\acr{pid} per generare un \index{\textit{pathname}}\textit{pathname} univoco,
+che non potrà essere replicato da un altro processo che usi la stessa
+funzione.
 
 Tutti i processi figli dello stesso processo padre sono detti
 \textit{sibling}, questa è una delle relazioni usate nel \textsl{controllo di
   sessione}, in cui si raggruppano i processi creati su uno stesso terminale,
 o relativi allo stesso login. Torneremo su questo argomento in dettaglio in
-\secref{cap:session}, dove esamineremo gli altri identificativi associati ad
+cap.~\ref{cha:session}, dove esamineremo gli altri identificativi associati ad
 un processo e le varie relazioni fra processi utilizzate per definire una
 sessione.
 
-Oltre al \acr{pid} e al \acr{ppid}, e a quelli usati per il controllo di
-sessione, ad ogni processo sono associati altri identificatori, usati per il
-controllo di accesso, che servono per determinare se il processo può o meno
-eseguire le operazioni richieste, a seconda dei privilegi e dell'identità di
-chi lo ha posto in esecuzione; su questi torneremo in dettaglii più avanti in
-\secref{sec:proc_perm}.
+Oltre al \acr{pid} e al \acr{ppid}, (e a quelli che vedremo in
+sez.~\ref{sec:sess_proc_group}, relativi al controllo di sessione), ad ogni
+processo vengono associati degli altri identificatori che vengono usati per il
+controllo di accesso.  Questi servono per determinare se un processo può
+eseguire o meno le operazioni richieste, a seconda dei privilegi e
+dell'identità di chi lo ha posto in esecuzione; l'argomento è complesso e sarà
+affrontato in dettaglio in sez.~\ref{sec:proc_perms}.
 
 
 \subsection{La funzione \func{fork}}
 \label{sec:proc_fork}
 
-La funzione \func{fork} è la funzione fondamentale della gestione dei
+La funzione \funcd{fork} è la funzione fondamentale della gestione dei
 processi: come si è detto l'unico modo di creare un nuovo processo è
 attraverso l'uso di questa funzione, essa quindi riveste un ruolo centrale
 tutte le volte che si devono scrivere programmi che usano il multitasking.  Il
 prototipo della funzione è:
-
 \begin{functions}
   \headdecl{sys/types.h} 
   \headdecl{unistd.h} 
   \funcdecl{pid\_t fork(void)} 
-  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;
-  \texttt{errno} può assumere i valori:
+  Crea un nuovo processo.
+  
+  \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
+  \item[\errcode{EAGAIN}] non ci sono risorse sufficienti per creare un altro
     processo (per allocare la tabella delle pagine e le strutture del task) o
     si è esaurito il numero di processi disponibili.
-  \item \macro{ENOMEM} non è stato possibile allocare la memoria per le
+  \item[\errcode{ENOMEM}] non è stato possibile allocare la memoria per le
     strutture necessarie al kernel per creare il nuovo processo.
-  \end{errlist}
+  \end{errlist}}
 \end{functions}
 
 Dopo il successo dell'esecuzione di una \func{fork} sia il processo padre che
-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} pertanto padre e
-figlio vedono variabili diverse.
+il processo figlio continuano ad essere eseguiti normalmente a partire
+dall'istruzione successiva alla \func{fork}; il processo figlio è però una
+copia del padre, e riceve una copia dei segmenti di testo, stack e dati (vedi
+sez.~\ref{sec:proc_mem_layout}), ed esegue esattamente lo stesso codice del
+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 per i due processi, è 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{\textit{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 fork è il \acr{pid} del processo figlio, mentre nel
-figlio è zero; in questo modo il programma può identificare se viene eseguito
-dal padre o dal figlio.  Si noti come la funzione \func{fork} ritorni
-\textbf{due} volte: una nel padre e una nel figlio. La sola differenza che si
-ha nei due processi è il valore di ritorno restituito dalla funzione, che nel
-padre è il \acr{pid} del figlio mentre nel figlio è zero; in questo modo il
-programma può identificare se viene eseguito dal padre o dal figlio.
-
-La scelta di questi valori non è casuale, un processo infatti può avere più
-figli, ed il valore di ritorno di \func{fork} è l'unico modo che permette di
-identificare quello appena creato; al contrario un figlio ha sempre un solo
-padre (il cui \acr{pid} può sempre essere ottenuto con \func{getppid}, vedi
-\secref{sec:proc_pid}) e si usa il valore nullo, che non può essere il
-\acr{pid} di nessun processo.
+ritorno della funzione \func{fork} è il \acr{pid} del processo figlio, mentre
+nel figlio è zero; in questo modo il programma può identificare se viene
+eseguito dal padre o dal figlio.  Si noti come la funzione \func{fork} ritorni
+\textbf{due} volte: una nel padre e una nel figlio. 
+
+La scelta di questi valori di ritorno non è casuale, un processo infatti può
+avere più figli, ed il valore di ritorno di \func{fork} è l'unico modo che gli
+permette di identificare quello appena creato; al contrario un figlio ha
+sempre un solo padre (il cui \acr{pid} può sempre essere ottenuto con
+\func{getppid}, vedi sez.~\ref{sec:proc_pid}) per cui si usa il valore nullo,
+che non è il \acr{pid} di nessun processo.
 
 \begin{figure}[!htb]
-  \footnotesize
-  \begin{lstlisting}{}
-#include <errno.h>       /* error definitions and routines */ 
-#include <stdlib.h>      /* C standard library */
-#include <unistd.h>      /* unix standard library */
-#include <stdio.h>       /* standard I/O library */
-#include <string.h>      /* string functions */
-
-/* Help printing routine */
-void usage(void);
-
-int main(int argc, char *argv[])
-{
-/* 
- * Variables definition  
- */
-    int nchild, i;
-    pid_t pid;
-    int wait_child  = 0;
-    int wait_parent = 0;
-    int wait_end    = 0;
-    ...        /* handling options */
-    nchild = atoi(argv[optind]);
-    printf("Test for forking %d child\n", nchild);
-    /* loop to fork children */
-    for (i=0; i<nchild; i++) {
-        if ( (pid = fork()) < 0) { 
-            /* on error exit */ 
-            printf("Error on %d child creation, %s\n", i+1, strerror(errno));
-            exit(-1); 
-        }
-        if (pid == 0) {   /* child */
-            printf("Child %d successfully executing\n", ++i);
-            if (wait_child) sleep(wait_child);
-            printf("Child %d, parent %d, exiting\n", i, getppid());
-            exit(0);
-        } else {          /* parent */
-            printf("Spawned %d child, pid %d \n", i+1, pid);
-            if (wait_parent) sleep(wait_parent);
-            printf("Go to next child \n");
-        }
-    }
-    /* normal exit */
-    if (wait_end) sleep(wait_end);
-    return 0;
-}
-  \end{lstlisting}
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+  \includecodesample{listati/ForkTest.c}
+  \end{minipage}
+  \normalsize
   \caption{Esempio di codice per la creazione di nuovi processi.}
   \label{fig:proc_fork_code}
 \end{figure}
@@ -327,58 +361,68 @@ int main(int argc, char *argv[])
 Normalmente la chiamata a \func{fork} può fallire solo per due ragioni, o ci
 sono già troppi processi nel sistema (il che di solito è sintomo che
 qualcos'altro non sta andando per il verso giusto) o si è ecceduto il limite
-sul numero totale di processi permessi all'utente (il valore della costante
-\macro{CHILD\_MAX} definito in \file{limits.h}, che fa riferimento ai processo
-con lo stesso \textit{real user id}).
+sul numero totale di processi permessi all'utente (vedi
+sez.~\ref{sec:sys_resource_limit}, ed in particolare
+tab.~\ref{tab:sys_rlimit_values}).
 
 L'uso di \func{fork} avviene secondo due modalità principali; la prima è
-quella in cui all'interno di un programma si creano processi figli per
-affidargli l'esecuzione di una certa sezione di codice, mentre il processo
-padre ne esegue un'altra. È il caso tipico dei server di rete in cui il padre
-riceve ed accetta le richieste da parte dei client, per ciascuna delle quali
-pone in esecuzione un figlio che è incaricato di fornire il servizio.
+quella in cui all'interno di un programma si creano processi figli cui viene
+affidata l'esecuzione di una certa sezione di codice, mentre il processo padre
+ne esegue un'altra. È il caso tipico dei programmi server (il modello
+\textit{client-server} è illustrato in sez.~\ref{sec:net_cliserv}) in cui il
+padre riceve ed accetta le richieste da parte dei programmi client, per
+ciascuna delle quali pone in esecuzione un figlio che è incaricato di fornire
+il servizio.
 
 La seconda modalità è quella in cui il processo vuole eseguire un altro
 programma; questo è ad esempio il caso della shell. In questo caso il processo
-crea un figlio la cui unica operazione è quella fare una \func{exec} (di cui
-parleremo in \secref{sec:proc_exec}) subito dopo la \func{fork}.
+crea un figlio la cui unica operazione è quella di fare una \func{exec} (di
+cui parleremo in sez.~\ref{sec:proc_exec}) subito dopo la \func{fork}.
 
 Alcuni sistemi operativi (il VMS ad esempio) combinano le operazioni di questa
 seconda modalità (una \func{fork} seguita da una \func{exec}) in un'unica
 operazione che viene chiamata \textit{spawn}. Nei sistemi unix-like è stato
-scelto di mantenere questa separazione, dato che, come visto per la prima
-modalità d'uso, esistono numerosi scenari in cui si può usare una \func{fork}
-senza bisogno di una \func{exec}. Inoltre anche nel caso della seconda
-modalità di operazioni, avere le due funzioni separate permette al figlio di
+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à 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 molto più
-flessibile la possibilità di modificare gli attributi del nuovo processo.
-
-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
+dell'output, identificatori) prima della \func{exec}, rendendo così
+relativamente facile intervenire sulle le modalità di esecuzione del nuovo
+programma.
+
+In fig.~\ref{fig:proc_fork_code} è riportato il corpo del codice del programma
+di esempio \cmd{forktest}, che permette di illustrare molte caratteristiche
+dell'uso della funzione \func{fork}. Il programma crea un numero di figli
+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://gapil.truelite.it/gapil_source.tgz}
+{\textsf{http://gapil.truelite.it/gapil\_source.tgz}}.
 
 Decifrato il numero di figli da creare, il ciclo principale del programma
-(\texttt{\small 28--40}) esegue in successione la creazione dei processi figli
+(\texttt{\small 24--40}) esegue in successione la creazione dei processi figli
 controllando il successo della chiamata a \func{fork} (\texttt{\small
-  29--31}); ciascun figlio (\texttt{\small 29--31}) si limita a stampare il
+  25--29}); ciascun figlio (\texttt{\small 31--34}) si limita a stampare il
 suo numero di successione, eventualmente attendere il numero di secondi
 specificato e scrivere un messaggio prima di uscire. Il processo padre invece
-(\texttt{\small 29--31}) stampa un messaggio di creazione, eventualmente
+(\texttt{\small 36--38}) stampa un messaggio di creazione, eventualmente
 attende il numero di secondi specificato, e procede nell'esecuzione del ciclo;
 alla conclusione del ciclo, prima di uscire, può essere specificato un altro
 periodo di attesa.
 
-Se eseguiamo il comando senza specificare attese (come si può notare in
-\texttt{\small 17--19} i valori di default specificano di non attendere),
-otterremo come output sul terminale:
+Se eseguiamo il comando\footnote{che è preceduto dall'istruzione \code{export
+    LD\_LIBRARY\_PATH=./} per permettere l'uso delle librerie dinamiche.}
+senza specificare attese (come si può notare in (\texttt{\small 17--19}) i
+valori predefiniti specificano di non attendere), otterremo come output sul
+terminale:
+
+\footnotesize
 \begin{verbatim}
-[piccardi@selidor sources]$ ./forktest 3
+[piccardi@selidor sources]$ export LD_LIBRARY_PATH=./; ./forktest 3
 Process 1963: forking 3 child
 Spawned 1 child, pid 1964 
 Child 1 successfully executing
@@ -393,21 +437,23 @@ Child 3, parent 1963, exiting
 Spawned 3 child, pid 1966 
 Go to next child 
 \end{verbatim} %$
-
-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
-primo\footnote{anche se nel kernel 2.4.x era stato introdotto un meccanismo
-  che metteva in esecuzione sempre il xxx per primo (TODO recuperare le
-  informazioni esatte)} 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 all'esecuzione del padre (con la stampa del passaggio al
+\normalsize
+
+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\index{\textit{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 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 all'esecuzione del padre (con la stampa del passaggio al
 ciclo successivo), mentre la terza volta è stato prima eseguito il figlio
 (fino alla conclusione) e poi il padre.
 
 In generale l'ordine di esecuzione dipenderà, oltre che dall'algoritmo di
-scheduling usato dal kernel, dalla particolare situazione in si trova la
+scheduling usato dal kernel, dalla particolare situazione in cui si trova la
 macchina al momento della chiamata, risultando del tutto impredicibile.
 Eseguendo più volte il programma di prova e producendo un numero diverso di
 figli, si sono ottenute situazioni completamente diverse, compreso il caso in
@@ -415,22 +461,26 @@ 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
-essere messi in esecuzione, e se è necessaria una qualche forma di precedenza
+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 conditions}.
+rischio di incorrere nelle cosiddette 
+\textit{race condition}\index{\textit{race~condition}} 
+(vedi sez.~\ref{sec:proc_race_cond}).
 
-Si noti inoltre che, come accennato, 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 33}) sono
-visibili solo al loro interno, 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).
+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 (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
 proviamo a redirigere su un file l'output del nostro programma di test, quello
 che otterremo è:
+
+\footnotesize
 \begin{verbatim}
 [piccardi@selidor sources]$ ./forktest 3 > output
 [piccardi@selidor sources]$ cat output
@@ -457,108 +507,119 @@ Go to next child
 Spawned 3 child, pid 1970 
 Go to next child 
 \end{verbatim}
+\normalsize
 che come si vede è completamente diverso da quanto ottenevamo sul terminale.
 
 Il comportamento delle varie funzioni di interfaccia con i file è analizzato
-in gran dettaglio in \capref{cha:file_unix_interface} e in
-\secref{cha:files_std_interface}. Qui basta accennare che si sono usate le
+in gran dettaglio in cap.~\ref{cha:file_unix_interface} e in
+cap.~\ref{cha:files_std_interface}. Qui basta accennare che si sono usate le
 funzioni standard della libreria del C che prevedono l'output bufferizzato; e
-questa bufferizzazione varia a seconda che si tratti di un file su disco (in
-cui il buffer viene scaricato su disco solo quando necessario) o di un
-terminale (nel qual caso il buffer viene scaricato ad ogni a capo).
+questa bufferizzazione (trattata in dettaglio in sez.~\ref{sec:file_buffering})
+varia a seconda che si tratti di un file su disco (in cui il buffer viene
+scaricato su disco solo quando necessario) o di un terminale (nel qual caso il
+buffer viene scaricato ad ogni carattere di a capo).
 
 Nel primo esempio allora avevamo che ad ogni chiamata a \func{printf} il
 buffer veniva scaricato, e le singole righe erano stampate a video subito dopo
 l'esecuzione della \func{printf}. Ma con la redirezione su file la scrittura
-non avviene più alla fine di ogni riga e l'output resta nel buffer, per questo
-motivo, dato che ogni figlio riceve una copia della memoria del padre, esso
-riceverà anche quanto c'è nel buffer delle funzioni di I/O, comprese le linee
-scritte dal padre fino allora. Così quando all'uscita del figlio il buffer
-viene scritto su disco, troveremo nel file anche tutto quello che il processo
-padre aveva scritto prima della sua creazione.  E alla fine del file, dato che
-in questo caso il padre esce per ultimo, troviamo anche l'output del padre.
-
-Ma l'esempio ci mostra un'altro aspetto fondamentale dell'interazione con i
-file, che era valido anche per l'esempio precedente, ma meno evidente; il
-fatto cioè che non solo processi diversi possono scrivere in contemporanea
-sullo stesso file (l'argomento della condivisione dei file in unix è trattato
-in dettaglio in \secref{sec:file_sharing}), ma anche che, a differenza di
-quanto avviene per le variabili, la posizione corrente sul file è condivisa 
-fra il padre e tutti i processi figli. 
+non avviene più alla fine di ogni riga e l'output resta nel buffer. Dato che
+ogni figlio riceve una copia della memoria del padre, esso riceverà anche
+quanto c'è nel buffer delle funzioni di I/O, comprese le linee scritte dal
+padre fino allora. Così quando il buffer viene scritto su disco all'uscita del
+figlio, troveremo nel file anche tutto quello che il processo padre aveva
+scritto prima della sua creazione.  E alla fine del file (dato che in questo
+caso il padre esce per ultimo) troveremo anche l'output completo del padre.
+
+L'esempio ci mostra un altro aspetto fondamentale dell'interazione con i file,
+valido anche per l'esempio precedente, ma meno evidente: il fatto cioè che non
+solo processi diversi possono scrivere in contemporanea sullo stesso file
+(l'argomento della condivisione dei file è trattato in dettaglio in
+sez.~\ref{sec:file_sharing}), ma anche che, a differenza di quanto avviene per
+le variabili, la posizione corrente sul file è condivisa fra il padre e tutti
+i processi figli.
 
 Quello che succede è che quando lo standard output del padre viene rediretto,
 lo stesso avviene anche per tutti i figli; la funzione \func{fork} infatti ha
-la caratteristica di duplicare (allo stesso modo in cui lo fa la funzione
-\func{dup}, trattata in \secref{sec:file_dup}) nei figli tutti i file
-descriptor aperti nel padre, il che comporta che padre e figli condividono
-le stesse voci della file table (per la spiegazione di questi termini si veda
-\secref{sec:file_sharing} e referenza a figura da fare) e quindi anche
-l'offset corrente nel file.
-
-In questo modo se un processo scrive sul file aggiornerà l'offset sulla file
-table, e tutti gli altri processi che condividono la file table vedranno il
-nuovo valore; in questo modo si evita, in casi come quello appena mostrato in
-cui diversi processi scrivono sullo stesso file, che l'output successivo di un
-processo vada a sovrapporsi a quello dei precedenti (l'output potrà risultare
-mescolato, ma non ci saranno parti perdute per via di una sovrascrittura).
+la caratteristica di duplicare nei figli tutti i file descriptor aperti nel
+padre (allo stesso modo in cui lo fa la funzione \func{dup}, trattata in
+sez.~\ref{sec:file_dup}), il che comporta che padre e figli condividono le
+stesse voci della \textit{file table} (per la spiegazione di questi termini si
+veda sez.~\ref{sec:file_sharing}) fra cui c'è anche la posizione corrente nel
+file.
+
+In questo modo se un processo scrive sul file aggiornerà la posizione corrente
+sulla \textit{file table}, e tutti gli altri processi, che vedono la stessa
+\textit{file table}, vedranno il nuovo valore. In questo modo si evita, in
+casi come quello appena mostrato in cui diversi processi scrivono sullo stesso
+file, che l'output successivo di un processo vada a sovrapporsi a quello dei
+precedenti: l'output potrà risultare mescolato, ma non ci saranno parti
+perdute per via di una sovrascrittura.
 
 Questo tipo di comportamento è essenziale in tutti quei casi in cui il padre
-crea un figlio ed attende la sua conclusione per proseguire, ed entrambi
-scrivono sullo stesso file, ad esempio lo standard output (un caso tipico è la
-shell). Se l'output viene rediretto con questo comportamento avremo che il
-padre potrà continuare a scrivere automaticamente in coda a quanto scritto dal
-figlio; se così non fosse ottenere questo comportamento sarebbe estremamente
-complesso necessitando di una qualche forma di comunicazione fra i due
-processi.
+crea un figlio e attende la sua conclusione per proseguire, ed entrambi
+scrivono sullo stesso file (un caso tipico è la shell quando lancia un
+programma, il cui output va sullo standard output). 
+
+In questo modo, anche se l'output viene rediretto, il padre potrà sempre
+continuare a scrivere in coda a quanto scritto dal figlio in maniera
+automatica; se così non fosse ottenere questo comportamento sarebbe
+estremamente complesso necessitando di una qualche forma di comunicazione fra
+i due processi per far riprendere al padre la scrittura al punto giusto.
 
 In generale comunque non è buona norma far scrivere più processi sullo stesso
-file senza una qualche forma di sincronizzazione in quanto, come visto con il
-nostro esempio, le varie scritture risulteranno mescolate fra loro in una
-sequenza impredicibile. Le modalità con cui in genere si usano i file dopo una
-\func{fork} sono sostanzialmente due:
-\begin{enumerate}
+file senza una qualche forma di sincronizzazione in quanto, come visto anche
+con il nostro esempio, le varie scritture risulteranno mescolate fra loro in
+una sequenza impredicibile. Per questo le modalità con cui in genere si usano
+i file dopo una \func{fork} sono sostanzialmente due:
+\begin{enumerate*}
 \item Il processo padre aspetta la conclusione del figlio. In questo caso non
   è necessaria nessuna azione riguardo ai file, in quanto la sincronizzazione
-  degli offset dopo eventuali operazioni di lettura e scrittura effettuate dal
-  figlio è automatica.
+  della posizione corrente dopo eventuali operazioni di lettura e scrittura
+  effettuate dal figlio è automatica.
 \item L'esecuzione di padre e figlio procede indipendentemente. In questo caso
-  ciascuno dei due deve chiudere i file che non gli servono una volta che la
-  \func{fork} è stata eseguita, per evitare ogni forma di interferenza.
-\end{enumerate}
+  ciascuno dei due processi deve chiudere i file che non gli servono una volta
+  che la \func{fork} è stata eseguita, per evitare ogni forma di interferenza.
+\end{enumerate*}
 
 Oltre ai file aperti i processi figli ereditano dal padre una serie di altre
-proprietà comuni; in dettaglio avremo che dopo l'esecuzione di una \func{fork}
-padre e figlio avranno in comune:
-\begin{itemize}
-\item i file aperti (e gli eventuali flag di \textit{close-on-exec} se
-  settati).
-\item gli identificatori per il controllo di accesso: il \textit{real user
-    id}, il \textit{real group id}, l'\textit{effective user id},
-  l'\textit{effective group id} e i \textit{supplementary group id} (vedi
-  \secref{sec:proc_user_group}).
+proprietà; la lista dettagliata delle proprietà che padre e figlio hanno in
+comune dopo l'esecuzione di una \func{fork} è la seguente:
+\begin{itemize*}
+\item i file aperti e gli eventuali flag di
+  \textit{close-on-exec}\index{\textit{close-on-exec}} impostati (vedi
+  sez.~\ref{sec:proc_exec} e sez.~\ref{sec:file_fcntl});
+\item gli identificatori per il controllo di accesso: l'\textsl{user-ID
+    reale}, il \textsl{group-ID reale}, l'\textsl{user-ID effettivo}, il
+  \textsl{group-ID effettivo} ed i \textit{group-ID supplementari} (vedi
+  sez.~\ref{sec:proc_access_id});
 \item gli identificatori per il controllo di sessione: il \textit{process
-    group id} e il \textit{session id} e il terminale di controllo (vedi
-  \secref{sec:sess_xxx} e \secref{sec:sess_xxx}).
-\item i flag di \acr{suid} e \acr{sgid} (vedi \secref{sec:file_suid_sgid}).
+    group-ID} e il \textit{session id} ed il terminale di controllo (vedi
+  sez.~\ref{sec:sess_proc_group});
 \item la directory di lavoro e la directory radice (vedi
-  \secref{sec:file_work_dir}).
-\item la maschera dei permessi di creazione (vedi \secref{sec:file_umask}).
-\item la maschera dei segnali.
-\item i segmenti di memoria condivisa agganciati al processo. 
-\item i limiti sulle risorse
-\item le variabili di ambiente (vedi \secref{sec:proc_environ}).
-\end{itemize}
-le differenze invece sono:
-\begin{itemize}
-\item il valore di ritorno di \func{fork}.
-\item il \textit{process id}. 
-\item il \textit{parent process id} (quello del figlio viene settato al
-  \acr{pid} del padre).
-\item i valori dei tempi di esecuzione (\var{tms\_utime}, \var{tms\_stime},
-  \var{tms\_cutime}, \var{tms\_uetime}) che nel figlio sono posti a zero.
-\item i \textit{file lock}, che non vengono ereditati dal figlio.
-\item gli allarmi pendenti, che per il figlio vengono cancellati.
-\end{itemize}
+  sez.~\ref{sec:file_work_dir} e sez.~\ref{sec:file_chroot});
+\item la maschera dei permessi di creazione (vedi sez.~\ref{sec:file_umask});
+\item la maschera dei segnali bloccati (vedi sez.~\ref{sec:sig_sigmask}) e le
+  azioni installate (vedi sez.~\ref{sec:sig_gen_beha});
+\item i segmenti di memoria condivisa agganciati al processo (vedi
+  sez.~\ref{sec:ipc_sysv_shm});
+\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit});
+\item le priorità real-time e le affinità di processore (vedi
+  sez.~\ref{sec:proc_real_time});
+\item le variabili di ambiente (vedi sez.~\ref{sec:proc_environ}).
+\end{itemize*}
+Le differenze fra padre e figlio dopo la \func{fork} invece sono:
+\begin{itemize*}
+\item il valore di ritorno di \func{fork};
+\item il \acr{pid} (\textit{process id});
+\item il \acr{ppid} (\textit{parent process id}), quello del figlio viene
+  impostato al \acr{pid} del padre;
+\item i valori dei tempi di esecuzione della struttura \struct{tms} (vedi
+  sez.~\ref{sec:sys_cpu_times}) che nel figlio sono posti a zero;
+\item i \textit{lock} sui file (vedi sez.~\ref{sec:file_locking}), che non
+  vengono ereditati dal figlio;
+\item gli allarmi ed i segnali pendenti (vedi sez.~\ref{sec:sig_gen_beha}), che
+  per il figlio vengono cancellati.
+\end{itemize*}
 
 
 \subsection{La funzione \func{vfork}}
@@ -575,72 +636,78 @@ ritornare o uscire con \func{exit} ma usare esplicitamente \func{\_exit}.
 Questa funzione è un rimasuglio dei vecchi tempi in cui eseguire una
 \func{fork} comportava anche la copia completa del segmento dati del processo
 padre, che costituiva un inutile appesantimento in tutti quei casi in cui la
-\func{fork} veniva fatto solo per poi eseguire una \func{exec}. La funzione
+\func{fork} veniva fatta solo per poi eseguire una \func{exec}. La funzione
 venne introdotta in BSD per migliorare le prestazioni.
 
-Dato che Linux supporta il \textit{copy on write} la perdita di prestazioni è
+Dato che Linux supporta il \textit{copy on
+  write}\index{\textit{copy~on~write}} la perdita di prestazioni è
 assolutamente trascurabile, e l'uso di questa funzione (che resta un caso
-speciale della funzione \func{clone}), è deprecato, per questo eviteremo di
-trattarla ulteriormente.
+speciale della system call \func{\_\_clone}) è deprecato; per questo eviteremo
+di trattarla ulteriormente.
 
 
-\subsection{La conclusione di un processo.}
+\subsection{La conclusione di un processo}
 \label{sec:proc_termination}
 
-In \secref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
-concludere un programma, ma dal punto di vista del programma stesso; avendo a
-che fare con un sistema multitasking occorre adesso affrontare l'argomento dal
-punto di vista generale di come il sistema gestisce la conclusione dei
-processi.
+In sez.~\ref{sec:proc_conclusion} abbiamo già affrontato le modalità con cui
+chiudere un programma, ma dall'interno del programma stesso; avendo a che fare
+con un sistema multitasking resta da affrontare l'argomento dal punto di vista
+di come il sistema gestisce la conclusione dei processi.
 
-Abbiamo già visto in \secref{sec:proc_conclusion} le tre modalità con cui un
+Abbiamo visto in sez.~\ref{sec:proc_conclusion} le tre modalità con cui un
 programma viene terminato in maniera normale: la chiamata di \func{exit} (che
 esegue le funzioni registrate per l'uscita e chiude gli stream), il ritorno
 dalla funzione \func{main} (equivalente alla chiamata di \func{exit}), e la
 chiamata ad \func{\_exit} (che passa direttamente alle operazioni di
 terminazione del processo da parte del kernel).
 
-Ma oltre alla conclusione normale abbiamo accennato che esistono anche delle
+Ma abbiamo accennato che oltre alla conclusione normale esistono anche delle
 modalità di conclusione anomala; queste sono in sostanza due: il programma può
 chiamare la funzione \func{abort} per invocare una chiusura anomala, o essere
 terminato da un segnale.  In realtà anche la prima modalità si riconduce alla
 seconda, dato che \func{abort} si limita a generare il segnale
-\macro{SIGABRT}.
+\const{SIGABRT}.
 
 Qualunque sia la modalità di conclusione di un processo, il kernel esegue
 comunque una serie di operazioni: chiude tutti i file aperti, rilascia la
 memoria che stava usando, e così via; l'elenco completo delle operazioni
 eseguite alla chiusura di un processo è il seguente:
-\begin{itemize}
-\item tutti i descrittori dei file sono chiusi.
-\item viene memorizzato lo stato di terminazione del processo.
-\item ad ogni processo figlio viene assegnato un nuovo padre.
-\item viene inviato il segnale \macro{SIGCHLD} al processo padre.
-\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.
-\item se la conclusione di un processo rende orfano un \textit{process group}
-  ciascun membro del gruppo viene bloccato, e poi gli vengono inviati in
-  successione i segnali \macro{SIGHUP} e \macro{SIGCONT}.
-\end{itemize}
-ma al di la di queste operazioni è necessario poter disporre di un meccanismo
-ulteriore che consenta di sapere come questa terminazione è avvenuta; dato che
-in un sistema unix-like tutto viene gestito attraverso i processi il
-meccanismo scelto consiste nel riportare lo stato di terminazione
-(\textit{termination status}) di cui sopra al processo padre.
-
-Nel caso di conclusione normale, lo stato di uscita del processo viene
+\begin{itemize*}
+\item tutti i file descriptor sono chiusi;
+\item viene memorizzato lo stato di terminazione del processo;
+\item ad ogni processo figlio viene assegnato un nuovo padre (in genere
+  \cmd{init});
+\item viene inviato il segnale \const{SIGCHLD} al processo padre (vedi
+  sez.~\ref{sec:sig_sigchld});
+\item se il processo è un leader di sessione ed il suo terminale di controllo
+  è quello della sessione viene mandato un segnale di \const{SIGHUP} a tutti i
+  processi del gruppo di \textit{foreground} e il terminale di controllo viene
+  disconnesso (vedi sez.~\ref{sec:sess_ctrl_term});
+\item se la conclusione di un processo rende orfano un \textit{process
+    group} ciascun membro del gruppo viene bloccato, e poi gli vengono
+  inviati in successione i segnali \const{SIGHUP} e \const{SIGCONT}
+  (vedi ancora sez.~\ref{sec:sess_ctrl_term}).
+\end{itemize*}
+
+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
+scelto consiste nel riportare lo stato di terminazione (il cosiddetto
+\textit{termination status}) al processo padre.
+
+Nel caso di conclusione normale, abbiamo visto in
+sez.~\ref{sec:proc_conclusion} che lo stato di uscita del processo viene
 caratterizzato tramite il valore del cosiddetto \textit{exit status}, cioè il
 valore passato alle funzioni \func{exit} o \func{\_exit} (o dal valore di
 ritorno per \func{main}).  Ma se il processo viene concluso in maniera anomala
 il programma non può specificare nessun \textit{exit status}, ed è il kernel
 che deve generare autonomamente il \textit{termination status} per indicare le
-ragioni della conclusione anomala.  
+ragioni della conclusione anomala.
 
 Si noti la distinzione fra \textit{exit status} e \textit{termination status}:
 quello che contraddistingue lo stato di chiusura del processo e viene
 riportato attraverso le funzioni \func{wait} o \func{waitpid} (vedi
-\secref{sec:proc_wait}) è sempre quest'ultimo; in caso di conclusione normale
+sez.~\ref{sec:proc_wait}) è sempre quest'ultimo; in caso di conclusione normale
 il kernel usa il primo (nel codice eseguito da \func{\_exit}) per produrre il
 secondo.
 
@@ -651,15 +718,17 @@ che sia cos
 terminato (si potrebbe avere cioè quello che si chiama un processo
 \textsl{orfano}). 
 
-Questa complicazione viene superata facendo in modo che il processo figlio
-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
+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
 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 \textsl{adottivo}) cui riportare il suo stato
-di terminazione.  Come verifica di questo comportamento possiamo eseguire il
-comando \cmd{forktest} imponendo a ciascun processo figlio due
-secondi di attesa prima di uscire, il risultato è:
+avrà sempre un padre (nel caso possiamo parlare di un padre \textsl{adottivo})
+cui riportare il suo stato di terminazione.  Come verifica di questo
+comportamento possiamo eseguire il nostro programma \cmd{forktest} imponendo a
+ciascun processo figlio due secondi di attesa prima di uscire, il risultato è:
+
+\footnotesize
 \begin{verbatim}
 [piccardi@selidor sources]$ ./forktest -c2 3
 Process 1972: forking 3 child
@@ -676,6 +745,7 @@ Go to next child
 Child 2, parent 1, exiting
 Child 1, parent 1, exiting
 \end{verbatim}
+\normalsize
 come si può notare in questo caso il processo padre si conclude prima dei
 figli, tornando alla shell, che stampa il prompt sul terminale: circa due
 secondi dopo viene stampato a video anche l'output dei tre figli che
@@ -689,22 +759,24 @@ informazioni riguardo ai processi che sta terminando.
 
 Questo viene fatto mantenendo attiva la voce nella tabella dei processi, e
 memorizzando alcuni dati essenziali, come il \acr{pid}, i tempi di CPU usati
-dal processo (vedi \secref{sec:intro_unix_time}) e lo stato di terminazione
-\footnote{NdA verificare esattamente cosa c'è!}, mentre la memoria in uso ed i
-file aperti vengono rilasciati immediatamente. I processi che sono terminati,
-ma il cui stato di terminazione non è stato ancora ricevuto dal padre sono
-chiamati \textit{zombie}, essi restano presenti nella tabella dei processi ed
-in genere possono essere identificati dall'output di \cmd{ps} per la presenza
-di una \cmd{Z} nella colonna che ne indica lo stato. Quando il padre
-effettuerà la lettura dello stato di uscita anche questa informazione, non più
-necessaria, verrà scartata e la terminazione potrà dirsi completamente
-conclusa.
+dal processo (vedi sez.~\ref{sec:sys_unix_time}) e lo stato di terminazione,
+mentre la memoria in uso ed i file aperti vengono rilasciati immediatamente. I
+processi che sono terminati, ma il cui stato di terminazione non è stato
+ancora ricevuto dal padre sono chiamati \textit{zombie}\index{zombie}, essi
+restano presenti nella tabella dei processi ed in genere possono essere
+identificati dall'output di \cmd{ps} per la presenza di una \texttt{Z} nella
+colonna che ne indica lo stato (vedi tab.~\ref{tab:proc_proc_states}). Quando
+il padre effettuerà la lettura dello stato di uscita anche questa
+informazione, non più necessaria, verrà scartata e la terminazione potrà dirsi
+completamente conclusa.
 
 Possiamo utilizzare il nostro programma di prova per analizzare anche questa
-condizione: lanciamo il comando \cmd{forktest} in background, indicando al
-processo padre di aspettare 10 secondi prima di uscire; in questo caso, usando
-\cmd{ps} sullo stesso terminale (prima dello scadere dei 10 secondi)
-otterremo:
+condizione: lanciamo il comando \cmd{forktest} in \textit{background} (vedi
+sez.~\ref{sec:sess_job_control}), indicando al processo padre di aspettare 10
+secondi prima di uscire; in questo caso, usando \cmd{ps} sullo stesso
+terminale (prima dello scadere dei 10 secondi) otterremo:
+
+\footnotesize
 \begin{verbatim}
 [piccardi@selidor sources]$ ps T
   PID TTY      STAT   TIME COMMAND
@@ -715,152 +787,170 @@ otterremo:
   571 pts/0    Z      0:00 [forktest <defunct>]
   572 pts/0    R      0:00 ps T
 \end{verbatim} %$
-e come si vede, dato che non si è fatto nulla per riceverne lo stato di
-terminazione, i tre processi figli sono ancora presenti pur essendosi
-conclusi, con lo stato di zombie e l'indicazione che sono stati terminati.
-
-La possibilità di avere degli zombie deve essere tenuta sempre presente quando
-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
+\normalsize e come si vede, dato che non si è fatto nulla per riceverne lo
+stato di terminazione, i tre processi figli sono ancora presenti pur essendosi
+conclusi, con lo stato di zombie\index{zombie} e l'indicazione che sono stati
+terminati.
+
+La possibilità di avere degli zombie\index{zombie} deve essere tenuta sempre
+presente quando 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
-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.
+\func{wait}, vedi sez.~\ref{sec:sig_sigchld} e sez.~\ref{sec:proc_wait}).
+Questa operazione è necessaria perché anche se gli
+\textit{zombie}\index{zombie} non consumano risorse di memoria o processore,
+occupano comunque una voce nella tabella dei processi, che a lungo andare
+potrebbe esaurirsi.
 
 Si noti che quando un processo adottato da \cmd{init} termina, esso non
-diviene uno \textit{zombie}; questo perché una delle funzioni di \cmd{init} è
-appunto quella di chiamare la funzione \func{wait} per i processi cui fa da
-padre, completandone la terminazione. Questo è quanto avviene anche quando,
-come nel caso del precedente esempio con \cmd{forktest}, il padre termina con
-dei figli in stato di zombie: alla sua terminazione infatti tutti i suoi figli
-vengono ereditati (compresi gli zombie) verranno adottati da \cmd{init}, il
-quale provvederà a completarne la terminazione.
-
-Si tenga presente infine che siccome gli zombie sono processi già usciti, non
-c'è modo di eliminarli con il comando \cmd{kill}; l'unica possibilità è quella
-di terminare il processo che li ha generati, in modo che \cmd{init} possa
-adottarli e provvedere a concludere la terminazione.
-
-
-\subsection{Le funzioni \texttt{wait} e  \texttt{waitpid}}
+diviene uno \textit{zombie}\index{zombie}; questo perché una delle funzioni di
+\cmd{init} è appunto quella di chiamare la funzione \func{wait} per i processi
+cui fa da padre, completandone la terminazione. Questo è quanto avviene anche
+quando, come nel caso del precedente esempio con \cmd{forktest}, il padre
+termina con dei figli in stato di zombie\index{zombie}: alla sua terminazione
+infatti tutti i suoi figli (compresi gli zombie\index{zombie}) verranno
+adottati da \cmd{init}, il quale provvederà a completarne la terminazione.
+
+Si tenga presente infine che siccome gli zombie\index{zombie} sono processi
+già usciti, non c'è modo di eliminarli con il comando \cmd{kill}; l'unica
+possibilità di cancellarli dalla tabella dei processi è quella di terminare il
+processo che li ha generati, in modo che \cmd{init} possa adottarli e
+provvedere a concluderne la terminazione.
+
+
+\subsection{Le funzioni \func{wait} e  \func{waitpid}}
 \label{sec:proc_wait}
 
-Abbiamo già accennato come uno degli usi possibili delle capacità multitasking
-di un sistema unix-like consista nella creazione di programmi di tipo server,
-in cui un processo principale attende le richieste che vengono poi soddisfatte
-creando una serie di processi figli. Si è già sottolineato al paragrafo
-precedente come in questo caso diventi necessario gestire esplicitamente la
-conclusione dei vari processi figli onde evitare di riempire di
-\textit{zombie} la tabella dei processi; le funzioni deputate a questo compito
-sono sostanzialmente due, \func{wait} e \func{waitpid}. La prima, il cui
-prototipo è:
-
+Uno degli usi più comuni delle capacità multitasking di un sistema unix-like
+consiste nella creazione di programmi di tipo server, in cui un processo
+principale attende le richieste che vengono poi soddisfatte da una serie di
+processi figli. Si è già sottolineato al paragrafo precedente come in questo
+caso diventi necessario gestire esplicitamente la conclusione dei figli onde
+evitare di riempire di \textit{zombie}\index{zombie} la tabella dei processi;
+le funzioni deputate a questo compito sono sostanzialmente due, \funcd{wait} e
+\func{waitpid}. La prima, il cui prototipo è:
 \begin{functions}
 \headdecl{sys/types.h}
 \headdecl{sys/wait.h}
-\funcdecl{pid\_t wait(int * status)} 
+\funcdecl{pid\_t wait(int *status)} 
 
 Sospende il processo corrente finché un figlio non è uscito, o finché un
-segnale termina il processo o chiama una funzione di gestione. Se un figlio è
-già uscito la funzione ritorna immediatamente. Al ritorno lo stato di
-termininazione del processo viene salvato nella variabile puntata da
-\var{status} e tutte le informazioni relative al processo (vedi
-\secref{sec:proc_termination}) vengono rilasciate.
-
-La funzione restituisce il \acr{pid} del figlio in caso di successo e -1 in
-caso di errore; \var{errno} può assumere i valori:
+segnale termina il processo o chiama una funzione di gestione. 
+
+\bodydesc{La funzione restituisce il \acr{pid} del figlio in caso di successo
+  e -1 in caso di errore; \var{errno} può assumere i valori:
   \begin{errlist}
-  \item \macro{EINTR} la funzione è stata interrotta da un segnale.
-  \end{errlist}
+  \item[\errcode{EINTR}] la funzione è stata interrotta da un segnale.
+  \end{errlist}}
 \end{functions}
-è presente fin dalle prime versioni di unix; la funzione ritorna alla
-conclusione del primo figlio (o immediatamente se un figlio è già uscito). Nel
-caso un processo abbia più figli il valore di ritorno permette di identificare
-qual'è quello che è uscito.
-
-Questa funzione però ha il difetto di essere poco flessibile, in quanto
-ritorna all'uscita di un figlio qualunque. Nelle occasioni in cui è necessario
-attendere la conclusione di un processo specifico occorre predisporre un
-meccanismo che tenga conto dei processi già terminati, e ripeta la chiamata
-alla funzione nel caso il processo cercato sia ancora attivo.
-
-Per questo motivo lo standard POSIX.1 ha introdotto la funzione \func{waitpid}
-che effettua lo stesso servizio, ma dispone di una serie di funzionalità più
-ampie, legate anche al controllo di sessione.  Dato che è possibile ottenere
-lo stesso comportamento di \func{wait} si consiglia di utilizzare sempre
-questa funzione; il suo prototipo è:
-
+\noindent
+è presente fin dalle prime versioni di Unix; la funzione ritorna non appena un
+processo figlio termina. Se un figlio è già terminato la funzione ritorna
+immediatamente, se più di un figlio è terminato occorre chiamare la funzione
+più volte se si vuole recuperare lo stato di terminazione di tutti quanti.
+
+Al ritorno della funzione lo stato di terminazione del figlio viene salvato
+nella variabile puntata da \param{status} e tutte le risorse del kernel
+relative al processo (vedi sez.~\ref{sec:proc_termination}) vengono rilasciate.
+Nel caso un processo abbia più figli il valore di ritorno (il \acr{pid} del
+figlio) permette di identificare qual è quello che è uscito.
+
+Questa funzione ha il difetto di essere poco flessibile, in quanto ritorna
+all'uscita di un qualunque processo figlio. Nelle occasioni in cui è
+necessario attendere la conclusione di un processo specifico occorrerebbe
+predisporre un meccanismo che tenga conto dei processi già terminati, e
+provvedere a ripetere la chiamata alla funzione nel caso il processo cercato
+sia ancora attivo.
+
+Per questo motivo lo standard POSIX.1 ha introdotto la funzione
+\funcd{waitpid} che effettua lo stesso servizio, ma dispone di una serie di
+funzionalità più ampie, legate anche al controllo di sessione (si veda
+sez.~\ref{sec:sess_job_control}).  Dato che è possibile ottenere lo stesso
+comportamento di \func{wait} si consiglia di utilizzare sempre questa
+funzione, il cui prototipo è:
 \begin{functions}
 \headdecl{sys/types.h}
 \headdecl{sys/wait.h}
-\funcdecl{pid\_t waitpid(pid\_t pid, int * status, int options)} 
+\funcdecl{pid\_t waitpid(pid\_t pid, int *status, int options)} 
+Attende la conclusione di un processo figlio.
 
-La funzione restituisce il \acr{pid} del processo che è uscito, 0 se è stata
-specificata l'opzione \macro{WNOHANG} e il processo non è uscito e -1 per un
-errore, nel qual caso \var{errno} assumerà i valori:
+\bodydesc{La funzione restituisce il \acr{pid} del processo che è uscito, 0 se
+  è stata specificata l'opzione \const{WNOHANG} e il processo non è uscito e
+  -1 per un errore, nel qual caso \var{errno} assumerà i valori:
   \begin{errlist}
-  \item \macro{EINTR} se non è stata specificata l'opzione \macro{WNOHANG} e
+  \item[\errcode{EINTR}] se non è stata specificata l'opzione \const{WNOHANG} e
     la funzione è stata interrotta da un segnale.
-  \item \macro{ECHILD} il processo specificato da \var{pid} non esiste o non è
-    figlio del processo chiamante.
-  \end{errlist}
+  \item[\errcode{ECHILD}] il processo specificato da \param{pid} non esiste o
+    non è figlio del processo chiamante.
+  \end{errlist}}
 \end{functions}
 
 Le differenze principali fra le due funzioni sono che \func{wait} si blocca
 sempre fino a che un processo figlio non termina, mentre \func{waitpid} ha la
-possibilità si specificare un'opzione \macro{WNOHANG} che ne previene il
-blocco; inoltre \func{waitpid} può specificare quale processo attendere sulla
-base del valore specificato tramite la variabile \var{pid}, secondo lo
-specchietto riportato in \ntab:
+possibilità si specificare un'opzione \const{WNOHANG} che ne previene il
+blocco; inoltre \func{waitpid} può specificare in maniera flessibile quale
+processo attendere, sulla base del valore fornito dall'argomento \param{pid},
+secondo lo specchietto riportato in tab.~\ref{tab:proc_waidpid_pid}.
+
 \begin{table}[!htb]
   \centering
-  \begin{tabular}[c]{|c|p{10cm}|}
+  \footnotesize
+  \begin{tabular}[c]{|c|c|p{8cm}|}
     \hline
-    \textbf{Valore} & \textbf{Significato}\\
+    \textbf{Valore} & \textbf{Opzione} &\textbf{Significato}\\
     \hline
     \hline
-    $<-1$& attende per un figlio il cui \textit{process group} è uguale al
-    valore assoluto di \var{pid}. \\
-    $-1$ & attende per un figlio qualsiasi, usata in questa maniera è
-    equivalente a \func{wait}.\\ 
-    $0$  & attende per un figlio il cui \textit{process group} è uguale a
-    quello del processo chiamante. \\
-    $>0$ & attende per un figlio il cui \acr{pid} è uguale al
-    valore di \var{pid}.\\
+    $<-1$& -- & attende per un figlio il cui \textit{process group} (vedi
+    sez.~\ref{sec:sess_proc_group}) è uguale al
+    valore assoluto di \param{pid}. \\
+    $-1$ & \const{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
+    questa maniera è equivalente a \func{wait}.\\ 
+    $0$  & \const{WAIT\_MYPGRP} & attende per un figlio il cui \textit{process
+    group} è uguale a quello del processo chiamante. \\
+    $>0$ & -- &attende per un figlio il cui \acr{pid} è uguale al
+    valore di \param{pid}.\\
     \hline
   \end{tabular}
-  \caption{Significato dei valori del parametro \var{pid} della funzione
+  \caption{Significato dei valori dell'argomento \param{pid} della funzione
     \func{waitpid}.}
   \label{tab:proc_waidpid_pid}
 \end{table}
 
-Il comportamento di \func{waitpid} può essere modificato passando delle
-opportune opzioni tramite la variabile \var{option}. I valori possibili sono
-il già citato \macro{WNOHANG}, che previene il blocco della funzione quando il
-processo figlio non è terminato, e \macro{WUNTRACED} (usata per il controllo
-di sessione, trattato in \capref{cha:session}) che fa ritornare la funzione
-anche per i processi figli che sono bloccati ed il cui stato non è stato
-ancora riportato al padre. Il valore dell'opzione deve essere specificato come
-maschera binaria ottenuta con l'OR delle suddette costanti con zero.
+Il comportamento di \func{waitpid} può inoltre essere modificato passando
+delle opportune opzioni tramite l'argomento \param{option}. I valori possibili
+sono il già citato \const{WNOHANG}, che previene il blocco della funzione
+quando il processo figlio non è terminato, e \const{WUNTRACED} che permette di
+tracciare i processi bloccati.  Il valore dell'opzione deve essere specificato
+come maschera binaria ottenuta con l'OR delle suddette costanti con zero.
+
+In genere si utilizza \const{WUNTRACED} all'interno del controllo di sessione,
+(l'argomento è trattato in sez.~\ref{sec:sess_job_control}). In tal caso
+infatti la funzione ritorna, restituendone il \acr{pid}, quando c'è un
+processo figlio che è entrato in stato di sleep (vedi
+tab.~\ref{tab:proc_proc_states}) e del quale non si è ancora letto lo stato
+(con questa stessa opzione). In Linux sono previste altre opzioni non standard
+relative al comportamento con i thread, che riprenderemo in
+sez.~\ref{sec:thread_xxx}.
 
 La terminazione di un processo figlio è chiaramente un evento asincrono
 rispetto all'esecuzione di un programma e può avvenire in un qualunque
-momento, per questo motivo, come si è visto nella sezione precedente, una
-delle azioni prese dal kernel alla conclusione di un processo è quella di
-mandare un segnale di \macro{SIGCHLD} al padre. Questo segnale viene ignorato
-di default, ma costituisce il meccanismo di comunicazione asincrona con cui il
-kernel avverte un processo padre che uno dei suoi figli è terminato.
+momento. Per questo motivo, come accennato nella sezione precedente, una delle
+azioni prese dal kernel alla conclusione di un processo è quella di mandare un
+segnale di \const{SIGCHLD} al padre. L'azione predefinita (si veda
+sez.~\ref{sec:sig_base}) per questo segnale è di essere ignorato, ma la sua
+generazione costituisce il meccanismo di comunicazione asincrona con cui il
+kernel avverte il processo padre che uno dei suoi figli è terminato.
 
 In genere in un programma non si vuole essere forzati ad attendere la
 conclusione di un processo per proseguire, specie se tutto questo serve solo
-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}) nel qual
-caso, dato che il segnale è generato dalla terminazione un figlio, avremo la
-certezza che la chiamata a \func{wait} non si bloccherà.
+per leggerne lo stato di chiusura (ed evitare la presenza di
+\textit{zombie}\index{zombie}), per questo la modalità più usata per chiamare
+queste funzioni è quella di utilizzarle all'interno di un \textit{signal
+  handler} (vedremo un esempio di come gestire \const{SIGCHLD} con i segnali
+in sez.~\ref{sec:sig_example}). In questo 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]
   \centering
@@ -871,28 +961,32 @@ certezza che la chiamata a \func{wait} non si bloccher
     \hline
     \hline
     \macro{WIFEXITED(s)}   & Condizione vera (valore non nullo) per un processo
-    figlio che sia terminato normalmente. \\
+                             figlio che sia terminato normalmente. \\
     \macro{WEXITSTATUS(s)} & Restituisce gli otto bit meno significativi dello
-    stato di uscita del processo (passato attraverso \func{\_exit}, \func{exit}
-    o come valore di ritorno di \func{main}). Può essere valutata solo se
-    \macro{WIFEXITED} ha restituito un valore non nullo.\\
+                             stato di uscita del processo (passato attraverso
+                             \func{\_exit}, \func{exit} o come valore di
+                             ritorno di \func{main}). Può essere valutata solo
+                             se \val{WIFEXITED} ha restituito un valore non
+                             nullo.\\ 
     \macro{WIFSIGNALED(s)} & Vera se il processo figlio è terminato
-    in maniera anomala a causa di un segnale che non è stato catturato (vedi
-    \secref{sec:sig_notification}).\\
-    \macro{WTERMSIG(s)}    & restituisce il numero del segnale che ha causato
-    la terminazione anomala del processo.  Può essere valutata solo se
-    \macro{WIFSIGNALED} ha restituito un valore non nullo.\\
+                             in maniera anomala a causa di un segnale che non
+                             è stato catturato (vedi
+                             sez.~\ref{sec:sig_notification}).\\ 
+    \macro{WTERMSIG(s)}    & Restituisce il numero del segnale che ha causato
+                             la terminazione anomala del processo.  Può essere
+                             valutata solo se \val{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 non è definita dallo standard POSIX.1, ma è presente come estensione
-    sia in Linux che in altri unix}.\\
+                             file di \textit{core dump}. Può essere valutata
+                             solo se \val{WIFSIGNALED} ha restituito un valore
+                             non nullo.\footnotemark \\ 
     \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}. \\
-    \macro{WSTOPSIG(s)}    & restituisce il numero del segnale che ha bloccato
-    il processo, Può essere valutata solo se \macro{WIFSTOPPED} ha
-    restituito un valore non nullo. \\
+                             \func{waitpid} è bloccato. L'uso è possibile solo
+                             avendo specificato l'opzione \const{WUNTRACED}. \\
+    \macro{WSTOPSIG(s)}    & Restituisce il numero del segnale che ha bloccato
+                             il processo. Può essere valutata solo se
+                             \val{WIFSTOPPED} ha restituito un valore non
+                             nullo. \\ 
     \hline
   \end{tabular}
   \caption{Descrizione delle varie macro di preprocessore utilizzabili per 
@@ -900,147 +994,120 @@ certezza che la chiamata a \func{wait} non si bloccher
   \label{tab:proc_status_macro}
 \end{table}
 
-
-Entrambe le funzioni restituiscono lo stato di terminazione del processo
-tramite il puntatore \var{status} (se non interessa memorizzare lo stato si
-può passare un puntatore nullo). Il valore restituito da entrambe le funzioni
-dipende dall'implementazione, e tradizionalmente alcuni bit sono riservati per
-memorizzare lo stato di uscita (in genere 8) altri per indicare il segnale che
-ha causato la terminazione (in caso di conclusione anomala), uno per indicare
-se è stato generato un core file, etc.\footnote{le definizioni esatte si
-  possono trovare in \file{<bits/waitstatus.h} ma questo file non deve mai
-  essere usato direttamente, esso viene incluso attraverso
-  \file{<sys/wait.h>}}.  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}).
+\footnotetext{questa macro non è definita dallo standard POSIX.1, ma è
+    presente come estensione sia in Linux che in altri Unix.}
+
+Entrambe le funzioni di attesa restituiscono lo stato di terminazione del
+processo tramite il puntatore \param{status} (se non interessa memorizzare lo
+stato si può passare un puntatore nullo). Il valore restituito da entrambe le
+funzioni dipende dall'implementazione, e tradizionalmente alcuni bit (in
+genere 8) sono riservati per memorizzare lo stato di uscita, e altri per
+indicare il segnale che ha causato la terminazione (in caso di conclusione
+anomala), uno per indicare se è stato generato un core file, ecc.\footnote{le
+  definizioni esatte si possono trovare in \file{<bits/waitstatus.h>} ma
+  questo file non deve mai essere usato direttamente, esso viene incluso
+  attraverso \file{<sys/wait.h>}.}
+
+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 tab.~\ref{tab:proc_status_macro} (si tenga
+presente che queste macro prendono come parametro la variabile di tipo
+\ctyp{int} puntata da \param{status}).
 
 Si tenga conto che nel caso di conclusione anomala il valore restituito da
-\macro{WTERMSIG} può essere controllato contro le costanti definite in
-\file{signal.h}, e stampato usando le funzioni definite in
-\secref{sec:sig_strsignal}.
+\val{WTERMSIG} può essere confrontato con le costanti definite in
+\file{signal.h} ed elencate in tab.~\ref{tab:sig_signal_list}, e stampato
+usando le apposite funzioni trattate in sez.~\ref{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
-lettura dello stato di terminazione di un processo, analoghe a \func{wait} e
-\func{waitpid}, ma che prevedono un ulteriore parametro attraverso il quale il
-kernel può restituire al processo padre ulteriori informazioni sulle risorse
-usate dal processo terminato e dai vari figli.  Queste funzioni, che diventano
-accessibili definendo la costante \macro{\_USE\_BSD}, sono:
-
+Linux, seguendo un'estensione di BSD, supporta altre due funzioni per la
+lettura dello stato di terminazione di un processo, analoghe alle precedenti
+ma che prevedono un ulteriore argomento attraverso il quale il kernel può
+restituire al padre informazioni sulle risorse usate dal processo terminato e
+dai vari figli.  Le due funzioni sono \funcd{wait3} e \funcd{wait4}, che
+diventano accessibili definendo la macro \macro{\_USE\_BSD}; i loro prototipi
+sono:
 \begin{functions}
-  \headdecl{sys/times.h} 
-  \headdecl{sys/types.h} 
-  \headdecl{sys/wait.h}        
-  \headdecl{sys/resource.h}
-  \funcdecl{pid\_t wait4(pid\_t pid, int * status, int options, struct rusage
-    * rusage)} 
-  La funzione è identica a \func{waitpid} sia per comportamento che per i
-  valori dei parametri, ma restituisce in \var{rusage} un sommario delle
-  risorse usate dal processo (per i dettagli vedi \secref{sec:xxx_limit_res})
+  \headdecl{sys/times.h} \headdecl{sys/types.h} \headdecl{sys/wait.h}
+  \headdecl{sys/resource.h} 
+  
+  \funcdecl{pid\_t wait4(pid\_t pid, int *status, int options, struct rusage
+    *rusage)}   
+  È identica a \func{waitpid} sia per comportamento che per i valori degli
+  argomenti, ma restituisce in \param{rusage} un sommario delle risorse usate
+  dal processo.
+
   \funcdecl{pid\_t wait3(int *status, int options, struct rusage *rusage)}
-  Prima versione, equivalente a \func{wait4(-1, \&status, opt, rusage)} è
+  Prima versione, equivalente a \code{wait4(-1, \&status, opt, rusage)} è
   ormai deprecata in favore di \func{wait4}.
 \end{functions}
-la struttura \type{rusage} è definita in \file{sys/resource.h}, e viene
-utilizzata anche dalla funzione \func{getrusage} per ottenere le risorse di
-sistema usate dal processo; in Linux è definita come:
-\begin{figure}[!htb]
-  \footnotesize
-  \centering
-  \begin{minipage}[c]{15cm}
-    \begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-struct rusage {
-     struct timeval ru_utime; /* user time used */
-     struct timeval ru_stime; /* system time used */
-     long ru_maxrss;          /* maximum resident set size */
-     long ru_ixrss;           /* integral shared memory size */
-     long ru_idrss;           /* integral unshared data size */
-     long ru_isrss;           /* integral unshared stack size */
-     long ru_minflt;          /* page reclaims */
-     long ru_majflt;          /* page faults */
-     long ru_nswap;           /* swaps */
-     long ru_inblock;         /* block input operations */
-     long ru_oublock;         /* block output operations */
-     long ru_msgsnd;          /* messages sent */
-     long ru_msgrcv;          /* messages received */
-     long ru_nsignals;   ;    /* signals received */
-     long ru_nvcsw;           /* voluntary context switches */
-     long ru_nivcsw;          /* involuntary context switches */
-};
-    \end{lstlisting}
-  \end{minipage} 
-  \normalsize 
-  \caption{La struttura \texttt{rusage} per la lettura delle informazioni dei 
-    delle risorse usate da un processo.}
-  \label{fig:proc_rusage_struct}
-\end{figure}
-In genere includere esplicitamente \file{<sys/time.h>} non è più necessario,
-ma aumenta la portabilità, e serve in caso si debba accedere ai campi di
-\var{rusage} definiti come \type{struct timeval}. La struttura è ripresa dalla
-versione 4.3 Reno di BSD, attualmente (con il kernel 2.4.x) i soli campi che
-sono mantenuti sono: \var{ru\_utime}, \var{ru\_stime}, \var{ru\_minflt},
-\var{ru\_majflt}, e \var{ru\_nswap}.
+\noindent 
+la struttura \struct{rusage} è definita in \file{sys/resource.h}, e viene
+utilizzata anche dalla funzione \func{getrusage} (vedi
+sez.~\ref{sec:sys_resource_use}) per ottenere le risorse di sistema usate da un
+processo; la sua definizione è riportata in fig.~\ref{fig:sys_rusage_struct}.
 
 
-\subsection{Le funzioni \texttt{exec}}
+\subsection{Le funzioni \func{exec}}
 \label{sec:proc_exec}
 
 Abbiamo già detto che una delle modalità principali con cui si utilizzano i
-processi in unix è quella di usarli per lanciare nuovi programmi: questo viene
+processi in Unix è quella di usarli per lanciare nuovi programmi: questo viene
 fatto attraverso una delle funzioni della famiglia \func{exec}. Quando un
 processo chiama una di queste funzioni esso viene completamente sostituito dal
 nuovo programma; il \acr{pid} del processo non cambia, dato che non viene
-creato un nuovo processo, la funzione semplicemente rimpiazza lo stack, o
+creato un nuovo processo, la funzione semplicemente rimpiazza lo stack, lo
 heap, i dati ed il testo del processo corrente con un nuovo programma letto da
 disco. 
 
 Ci sono sei diverse versioni di \func{exec} (per questo la si è chiamata
-famiglia di funzioni) che possono essere usate per questo compito, che in
-realtà (come mostrato in \figref{fig:proc_exec_relat}), costituiscono un
-front-end a \func{execve}. Il prototipo  di quest'ultima è:
-
+famiglia di funzioni) che possono essere usate per questo compito, in realtà
+(come mostrato in fig.~\ref{fig:proc_exec_relat}), sono tutte un front-end a
+\funcd{execve}. Il prototipo di quest'ultima è:
 \begin{prototype}{unistd.h}
-{int execve(const char * filename, char * const argv [], char * const envp[])}
+{int execve(const char *filename, char *const argv[], char *const envp[])}
+  Esegue il programma contenuto nel file \param{filename}.
   
-  La funzione esegue il file o lo script indicato da \var{filename},
-  passandogli la lista di argomenti indicata da \var{argv} e come ambiente la
-  lista di stringhe indicata da \var{envp}; entrambe le liste devono essere
-  terminate da un puntatore nullo. I vettori degli argomenti e dell'ambiente
-  possono essere acceduti dal nuovo programma quando la sua funzione
-  \func{main} è dichiarata nella forma \func{main(int argc, char *argv[], char
-    *envp[])}.
-
-  La funzione ritorna -1 solo in caso di errore, nel qual caso caso la
-  \var{errno} può assumere i valori:
+  \bodydesc{La funzione ritorna solo in caso di errore, restituendo -1; nel
+    qual caso \var{errno} può assumere i valori:
   \begin{errlist}
-  \item \macro{EACCES} il file non è eseguibile, oppure il filesystem è
-    montato in \cmd{noexec}, oppure non è un file normale o un interprete.
-  \item \macro{EPERM} il file ha i bit \acr{suid} o \acr{sgid} ma l'utente non
-    è root o il filesystem è montato con \cmd{nosuid}, oppure
-  \item \macro{ENOEXEC} il file è in un formato non eseguibile o non
+  \item[\errcode{EACCES}] il file non è eseguibile, oppure il filesystem è
+    montato in \cmd{noexec}, oppure non è un file regolare o un interprete.
+  \item[\errcode{EPERM}] il file ha i bit \acr{suid} o \acr{sgid}, l'utente
+    non è root, il processo viene tracciato, o il filesystem è montato con
+    l'opzione \cmd{nosuid}.
+  \item[\errcode{ENOEXEC}] il file è in un formato non eseguibile o non
     riconosciuto come tale, o compilato per un'altra architettura.
-  \item \macro{ENOENT} il file o una delle librerie dinamiche o l'interprete
+  \item[\errcode{ENOENT}] il file o una delle librerie dinamiche o l'interprete
     necessari per eseguirlo non esistono.
-  \item \macro{ETXTBSY} L'eseguibile è aperto in scrittura da uno o più
+  \item[\errcode{ETXTBSY}] l'eseguibile è aperto in scrittura da uno o più
     processi. 
-  \item \macro{EINVAL} L'eseguibile ELF ha più di un segmento
-    \macro{PF\_INTERP}, cioè chiede di essere eseguito da più di un interprete.
-  \item \macro{ELIBBAD} Un interprete ELF non è in un formato  riconoscibile.
+  \item[\errcode{EINVAL}] l'eseguibile ELF ha più di un segmento
+    \const{PF\_INTERP}, cioè chiede di essere eseguito da più di un
+    interprete.
+  \item[\errcode{ELIBBAD}] un interprete ELF non è in un formato
+    riconoscibile.
+  \item[\errcode{E2BIG}] la lista degli argomenti è troppo grande.
   \end{errlist}
-  ed inoltre anche \macro{EFAULT}, \macro{ENOMEM}, \macro{EIO},
-  \macro{ENAMETOOLONG}, \macro{E2BIG}, \macro{ELOOP}, \macro{ENOTDIR},
-  \macro{ENFILE}, \macro{EMFILE}.
+  ed inoltre anche \errval{EFAULT}, \errval{ENOMEM}, \errval{EIO},
+  \errval{ENAMETOOLONG}, \errval{ELOOP}, \errval{ENOTDIR}, \errval{ENFILE},
+  \errval{EMFILE}.}
 \end{prototype}
 
-Le altre funzioni della famiglia servono per fornire all'utente una serie
-possibile di diverse interfacce per la creazione di un nuovo processo. I loro
-prototipi sono:
+La funzione \func{exec} esegue il file o lo script indicato da
+\param{filename}, passandogli la lista di argomenti indicata da \param{argv}
+e come ambiente la lista di stringhe indicata da \param{envp}; entrambe le
+liste devono essere terminate da un puntatore nullo. I vettori degli
+argomenti e dell'ambiente possono essere acceduti dal nuovo programma
+quando la sua funzione \func{main} è dichiarata nella forma
+\code{main(int argc, char *argv[], char *envp[])}.
 
+Le altre funzioni della famiglia servono per fornire all'utente una serie di
+possibili diverse interfacce per la creazione di un nuovo processo. I loro
+prototipi sono:
 \begin{functions}
 \headdecl{unistd.h}
 \funcdecl{int execl(const char *path, const char *arg, ...)} 
@@ -1051,21 +1118,22 @@ prototipi sono:
 \funcdecl{int execvp(const char *file, char *const argv[])} 
 
 Sostituiscono l'immagine corrente del processo con quella indicata nel primo
-argomento. I parametri successivi consentono di specificare gli argomenti a
+argomento. Gli argomenti successivi consentono di specificare gli argomenti a
 linea di comando e l'ambiente ricevuti dal nuovo processo.
 
-Queste funzioni ritornano solo in caso di errore, restituendo -1; nel qual
-caso \var{errno} andrà ad assumere i valori visti in precedenza per
-\func{execve}.
+\bodydesc{Queste funzioni ritornano solo in caso di errore, restituendo -1;
+  nel qual caso \var{errno} assumerà i valori visti in precedenza per
+  \func{execve}.}
 \end{functions}
 
 Per capire meglio le differenze fra le funzioni della famiglia si può fare
-riferimento allo specchietto riportato in \ntab. La prima differenza riguarda
-le modalità di passaggio dei parametri che poi andranno a costituire gli
-argomenti a linea di comando (cioè i valori di \var{argv} e \var{argc} visti
-dalla funzione \func{main} del programma chiamato). 
+riferimento allo specchietto riportato in tab.~\ref{tab:proc_exec_scheme}. La
+prima differenza riguarda le modalità di passaggio dei valori che poi andranno
+a costituire gli argomenti a linea di comando (cioè i valori di
+\param{argv} e \param{argc} visti dalla funzione \func{main} del programma
+chiamato).
 
-Queste modalità sono due e sono riassunte dagli mnenonici \func{v} e \func{l}
+Queste modalità sono due e sono riassunte dagli mnemonici \code{v} e \code{l}
 che stanno rispettivamente per \textit{vector} e \textit{list}. Nel primo caso
 gli argomenti sono passati tramite il vettore di puntatori \var{argv[]} a
 stringhe terminate con zero che costituiranno gli argomenti a riga di comando,
@@ -1073,9 +1141,7 @@ questo vettore \emph{deve} essere terminato da un puntatore nullo.
 
 Nel secondo caso le stringhe degli argomenti sono passate alla funzione come
 lista di puntatori, nella forma:
-\begin{lstlisting}[labelstep=0,frame=,indent=1cm]{}
-  char * arg0, char * arg1,  ..., char * argn, NULL
-\end{lstlisting}
+\includecodesnip{listati/char_list.c}
 che deve essere terminata da un puntatore nullo.  In entrambi i casi vale la
 convenzione che il primo argomento (\var{arg0} o \var{argv[0]}) viene usato
 per indicare il nome del file che contiene il programma che verrà eseguito.
@@ -1088,15 +1154,15 @@ per indicare il nome del file che contiene il programma che verr
     \multicolumn{1}{|c|}{\textbf{Caratteristiche}} & 
     \multicolumn{6}{|c|}{\textbf{Funzioni}} \\
     \hline
-    &\func{execl\ }&\func{execlp}&\func{execle}
-    &\func{execv\ }& \func{execvp}& \func{execve} \\
+    &\func{execl}\texttt{ }&\func{execlp}&\func{execle}
+    &\func{execv}\texttt{ }& \func{execvp}& \func{execve} \\
     \hline
     \hline
     argomenti a lista    &$\bullet$&$\bullet$&$\bullet$&&& \\
     argomenti a vettore  &&&&$\bullet$&$\bullet$&$\bullet$\\
     \hline
-    filename completo    &&$\bullet$&&&$\bullet$& \\ 
-    ricerca su \var{PATH}&$\bullet$&&$\bullet$&$\bullet$&&$\bullet$ \\
+    filename completo     &$\bullet$&&$\bullet$&$\bullet$&&$\bullet$\\ 
+    ricerca su \var{PATH} &&$\bullet$&&&$\bullet$& \\
     \hline
     ambiente a vettore   &&&$\bullet$&&&$\bullet$ \\
     uso di \var{environ} &$\bullet$&$\bullet$&&$\bullet$&$\bullet$& \\
@@ -1108,108 +1174,123 @@ per indicare il nome del file che contiene il programma che verr
 \end{table}
 
 La seconda differenza fra le funzioni riguarda le modalità con cui si
-specifica il programma che si vuole eseguire. Con lo mnemonico \func{p} si
+specifica il programma che si vuole eseguire. Con lo mnemonico \code{p} si
 indicano le due funzioni che replicano il comportamento della shell nello
-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}.
+specificare il comando da eseguire; quando l'argomento \param{file} non
+contiene una ``\texttt{/}'' 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
+relativo a permessi di accesso insufficienti (cioè l'esecuzione della
+sottostante \func{execve} ritorna un \errcode{EACCES}), la ricerca viene
+proseguita nelle eventuali ulteriori directory indicate in \var{PATH}; solo se
+non viene trovato nessun altro file viene finalmente restituito
+\errcode{EACCES}.
 
 Le altre quattro funzioni si limitano invece a cercare di eseguire il file
-indicato dal parametro \var{path}, che viene interpretato come il
-\textit{pathname} del programma.
+indicato dall'argomento \param{path}, che viene interpretato come il
+\index{\textit{pathname}}\textit{pathname} del programma.
 
 \begin{figure}[htb]
   \centering
-  \includegraphics[width=13cm]{img/exec_rel.eps}
-  \caption{La interrelazione fra le sei funzioni della famiglia \func{exec}}
+  \includegraphics[width=15cm]{img/exec_rel}
+  \caption{La interrelazione fra le sei funzioni della famiglia \func{exec}.}
   \label{fig:proc_exec_relat}
 \end{figure}
 
 La terza differenza è come viene passata la lista delle variabili di ambiente.
-Con lo mnemonico \func{e} vengono indicate quelle funzioni che necessitano di
-un vettore di parametri \var{envp[]} analogo a quello usato per gli argomenti
-a riga di comando (terminato quindi da un \macro{NULL}), le altre usano il
-valore della variabile \var{environ} (vedi \secref{sec:proc_environ}) del
-processo di partenza per costruire l'ambiente.
+Con lo mnemonico \texttt{e} vengono indicate quelle funzioni che necessitano
+di un vettore di parametri \var{envp[]} analogo a quello usato per gli
+argomenti a riga di comando (terminato quindi da un \val{NULL}), le altre
+usano il valore della variabile \var{environ} (vedi
+sez.~\ref{sec:proc_environ}) del processo di partenza per costruire
+l'ambiente.
 
 Oltre a mantenere lo stesso \acr{pid}, il nuovo programma fatto partire da
 \func{exec} assume anche una serie di altre proprietà del processo chiamante;
 la lista completa è la seguente:
-\begin{itemize}
-\item il \textit{process ID} (\acr{pid}) ed il \textit{parent process ID}
-  (\acr{ppid}).
-\item il \textit{real user ID} ed il \textit{real group ID} (vedi
-  \secref{sec:proc_user_group}).
-\item i \textit{supplementary group ID} (vedi \secref{sec:proc_user_group}).
-\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.
+\begin{itemize*}
+\item il \textit{process id} (\acr{pid}) ed il \textit{parent process id}
+  (\acr{ppid});
+\item l'\textsl{user-ID reale}, il \textit{group-ID reale} ed i
+  \textsl{group-ID supplementari} (vedi sez.~\ref{sec:proc_access_id});
+\item il \textit{session id} (\acr{sid}) ed il \textit{process group-ID}
+  (\acr{pgid}), vedi sez.~\ref{sec:sess_proc_group};
+\item il terminale di controllo (vedi sez.~\ref{sec:sess_ctrl_term});
+\item il tempo restante ad un allarme (vedi sez.~\ref{sec:sig_alarm_abort});
 \item la directory radice e la directory di lavoro corrente (vedi
-  \secref{sec:file_work_dir}).
+  sez.~\ref{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_xxx}).
+  sez.~\ref{sec:file_umask}) ed i \textit{lock} sui file (vedi
+  sez.~\ref{sec:file_locking});
 \item i segnali sospesi (\textit{pending}) e la maschera dei segnali (si veda
-  \secref{sec:sig_xxx}).
-\item i limiti sulle risorse (vedi \secref{sec:limits_xxx})..
+  sez.~\ref{sec:sig_sigmask});
+\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit});
 \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 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}).
-
-La gestione dei file aperti dipende dal valore del flag di
-\textit{close-on-exec} per ciascun file descriptor (si veda
-\secref{sec:file_xxx}); i file per cui è settato vengono chiusi, tutti gli
-altri file restano aperti. Questo significa che il comportamento di default è
-che i file 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
+  \var{tms\_cutime}, \var{tms\_ustime} (vedi sez.~\ref{sec:sys_cpu_times}).
+\end{itemize*}
+
+Inoltre i segnali che sono stati impostati per essere ignorati nel processo
+chiamante mantengono la stessa impostazione pure nel nuovo programma, tutti
+gli altri segnali vengono impostati alla loro azione predefinita. Un caso
+speciale è il segnale \const{SIGCHLD} che, quando impostato a
+\const{SIG\_IGN}, può anche non essere reimpostato a \const{SIG\_DFL} (si veda
+sez.~\ref{sec:sig_gen_beha}).
+
+La gestione dei file aperti dipende dal valore che ha il flag di
+\textit{close-on-exec}\index{\textit{close-on-exec}} (vedi anche
+sez.~\ref{sec:file_fcntl}) per ciascun file descriptor. I file per cui è
+impostato vengono chiusi, tutti gli altri file restano aperti. Questo
+significa che il comportamento predefinito è che i file restano aperti
+attraverso una \func{exec}, a meno di una chiamata esplicita a \func{fcntl}
+che imposti il suddetto flag.
+
+Per le directory, lo standard POSIX.1 richiede che esse vengano chiuse
 attraverso una \func{exec}, in genere questo è fatto dalla funzione
-\func{opendir} che effettua da sola il settaggio del flag di
-\textit{close-on-exec} sulle directory che apre, in maniera trasparente
-all'utente.
+\func{opendir} (vedi sez.~\ref{sec:file_dir_read}) che effettua da sola
+l'impostazione del flag di
+\textit{close-on-exec}\index{\textit{close-on-exec}} sulle directory che apre,
+in maniera trasparente all'utente.
 
-Abbiamo detto che il \textit{real user ID} ed il \textit{real group ID}
+Abbiamo detto che l'\textsl{user-ID reale} ed il \textsl{group-ID reale}
 restano gli stessi all'esecuzione di \func{exec}; lo stesso vale per
-l'\textit{effective user ID} ed l'\textit{effective group ID}, tranne il caso
-in cui il file che si va ad eseguire ha o il \acr{suid} bit o lo \acr{sgid}
-bit settato, nel qual caso \textit{effective user ID} e \textit{effective
-  group ID} vengono settati rispettivamente all'utente o al gruppo cui il file
-appartiene (per i dettagli vedi \secref{sec:proc_perms}).
+l'\textsl{user-ID effettivo} ed il \textsl{group-ID effettivo} (il significato
+di questi identificatori è trattato in sez.~\ref{sec:proc_access_id}), tranne
+quando il file che si va ad eseguire abbia o il \acr{suid} bit o lo \acr{sgid}
+bit impostato, in questo caso l'\textsl{user-ID effettivo} ed il
+\textsl{group-ID effettivo} vengono impostati rispettivamente all'utente o al
+gruppo cui il file appartiene (per i dettagli vedi sez.~\ref{sec:proc_perms}).
 
 Se il file da eseguire è in formato \emph{a.out} e necessita di librerie
-condivise, viene lanciato il \textit{linker} dinamico \cmd{ld.so} prima del
-programma per caricare le librerie necessarie ed effettuare il link
+condivise, viene lanciato il \textit{linker} dinamico \cmd{/lib/ld.so} prima
+del programma per caricare le librerie necessarie ed effettuare il link
 dell'eseguibile. Se il programma è in formato ELF per caricare le librerie
-dinamiche viene usato l'interprete indicato nel segmento \macro{PT\_INTERP},
+dinamiche viene usato l'interprete indicato nel segmento \const{PT\_INTERP},
 in genere questo è \file{/lib/ld-linux.so.1} per programmi linkati con le
-\emph{libc5}, e \file{/lib/ld-linux.so.2} per programmi linkati con le
-\emph{glibc}. Infine nel caso il file sia uno script esso deve iniziare con
-una linea nella forma \cmd{\#!/path/to/interpreter} dove l'interprete indicato
-deve esse un valido programma (binario, non un altro script) che verrà
-chiamato come se si fosse eseguito il comando \cmd{interpreter [arg]
-  filename}.
+\acr{libc5}, e \file{/lib/ld-linux.so.2} per programmi linkati con le
+\acr{glibc}. 
+
+Infine nel caso il file sia uno script esso deve iniziare con una linea nella
+forma \cmd{\#!/path/to/interpreter [argomenti]} dove l'interprete indicato
+deve essere un programma valido (binario, non un altro script) che verrà
+chiamato come se si fosse eseguito il comando \cmd{interpreter [argomenti]
+  filename}.\footnote{si tenga presente che con Linux quanto viene scritto
+  come \texttt{argomenti} viene passato all'inteprete come un unico argomento
+  con una unica stringa di lunghezza massima di 127 caratteri e se questa
+  dimensione viene ecceduta la stringa viene troncata; altri Unix hanno
+  dimensioni massime diverse, e diversi comportamenti, ad esempio FreeBSD
+  esegue la scansione della riga e la divide nei vari argomenti e se è troppo
+  lunga restitituisce un errore di \const{ENAMETOOLONG}, una comparazione dei
+  vari comportamenti si trova su
+  \href{http://www.in-ulm.de/~mascheck/various/shebang/}
+  {\texttt{http://www.in-ulm.de/\tild mascheck/various/shebang/}}.}
 
 Con la famiglia delle \func{exec} si chiude il novero delle funzioni su cui è
-basato il controllo dei processi in unix: con \func{fork} si crea un nuovo
-processo, con \func{exec} si avvia un nuovo programma, con \func{exit} e
-\func{wait} si effettua e si gestisce la conclusione dei programmi. Tutte le
-altre funzioni sono ausiliarie e servono la lettura e il settaggio dei vari
-parametri connessi ai processi.
+basata la gestione dei processi in Unix: con \func{fork} si crea un nuovo
+processo, con \func{exec} si lancia un nuovo programma, con \func{exit} e
+\func{wait} si effettua e verifica la conclusione dei processi. Tutte le
+altre funzioni sono ausiliarie e servono per la lettura e l'impostazione dei
+vari parametri connessi ai processi.
 
 
 
@@ -1217,20 +1298,24 @@ parametri connessi ai processi.
 \label{sec:proc_perms}
 
 In questa sezione esamineremo le problematiche relative al controllo di
-accesso dal punto di vista del processi; vedremo quali sono gli identificatori
+accesso dal punto di vista dei processi; vedremo quali sono gli identificatori
 usati, come questi possono essere modificati nella creazione e nel lancio di
-nuovi processi, e le varie funzioni per la loro manipolazione diretta e tutte
-le problematiche connesse alla gestione accorta dei privilegi.
-
-
-\subsection{Utente e gruppo di un processo}
-\label{sec:proc_user_group}
-
-Come accennato in \secref{sec:intro_multiuser} il modello base\footnote{in
-  realtà esistono estensioni di questo modello, che lo rendono più flessibile
-  e controllabile, come le \textit{capabilities}, le ACL per i file o il
-  modello a ``... NdT riprendere i dati'' di SELinux} di sicurezza di un
-sistema unix-like è fondato sui concetti di utente e gruppo, e sulla
+nuovi processi, le varie funzioni per la loro manipolazione diretta e tutte le
+problematiche connesse ad una gestione accorta dei privilegi.
+
+
+\subsection{Gli identificatori del controllo di accesso}
+\label{sec:proc_access_id}
+
+Come accennato in sez.~\ref{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; inoltre basandosi sul
+  lavoro effettuato con SELinux, a partire dal kernel 2.5.x, è iniziato lo
+  sviluppo di una infrastruttura di sicurezza, il \textit{Linux Security
+    Modules}, o LSM, in grado di fornire diversi agganci a livello del kernel
+  per modularizzare tutti i possibili controlli di accesso.} 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
 utenti, per i quali invece vengono effettuati i vari controlli di accesso.
@@ -1240,128 +1325,1423 @@ utenti, per i quali invece vengono effettuati i vari controlli di accesso.
 %notevole flessibilità, 
 
 Abbiamo già accennato come il sistema associ ad ogni utente e gruppo due
-identificatori univoci, lo \acr{uid} e il \acr{gid}; questi servono al kernel
-per identificare uno specifico utente o un gruppo di utenti, per poi poter
-controllare che essi siano autorizzati a compiere le operazioni richieste. 
-
-In \secref{sec:file_access_control} vedremo ad esempio come anche ad ogni file
-vengano associati un utente ed un gruppo (i suoi \textsl{proprietari},
-indicati appunto tramite un \acr{uid} ed un \acr{gid}) che vengono controllati
-dal kernel nella gestione dei permessi di accesso. 
+identificatori univoci, lo user-ID ed il group-ID; questi servono al kernel per
+identificare uno specifico utente o un gruppo di utenti, per poi poter
+controllare che essi siano autorizzati a compiere le operazioni richieste.  Ad
+esempio in sez.~\ref{sec:file_access_control} vedremo come ad ogni file vengano
+associati un utente ed un gruppo (i suoi \textsl{proprietari}, indicati
+appunto tramite un \acr{uid} ed un \acr{gid}) che vengono controllati dal
+kernel nella gestione dei permessi di accesso.
 
 Dato che tutte le operazioni del sistema vengono compiute dai processi, è
 evidente che per poter implementare un controllo sulle operazioni occorre
-anche poter identificare chi ha lanciato un certo processo, e pertanto anche a
-ciascuno di essi è associato un utente e a un gruppo. Un semplice controllo di
-una corrispondenza fra identificativi però non garantisce sufficiente
-flessibilità per tutti quei casi in cui è necessario poter disporre di
-privilegi diversi, o dover impersonare un altro utente per un limitato insieme
-di operazioni.
+anche poter identificare chi è che ha lanciato un certo programma, e pertanto
+anche a ciascun processo dovrà essere associato un utente e un gruppo.
+
+Un semplice controllo di una corrispondenza fra identificativi non garantisce
+però sufficiente flessibilità per tutti quei casi in cui è necessario poter
+disporre di privilegi diversi, o dover impersonare un altro utente per un
+limitato insieme di operazioni. Per questo motivo in generale tutti gli Unix
+prevedono che i processi abbiano almeno due gruppi di identificatori, chiamati
+rispettivamente \textit{real} ed \textit{effective} (cioè \textsl{reali} ed
+\textsl{effettivi}). Nel caso di Linux si aggiungono poi altri due gruppi, il
+\textit{saved} (\textsl{salvati}) ed il \textit{filesystem} (\textsl{di
+  filesystem}), secondo la situazione illustrata in
+tab.~\ref{tab:proc_uid_gid}.
+
+\begin{table}[htb]
+  \footnotesize
+  \centering
+  \begin{tabular}[c]{|c|c|l|p{7.3cm}|}
+    \hline
+    \textbf{Suffisso} & \textbf{Gruppo} & \textbf{Denominazione} 
+                                        & \textbf{Significato} \\ 
+    \hline
+    \hline
+    \acr{uid}   & \textit{real} & \textsl{user-ID reale} 
+                & indica l'utente che ha lanciato il programma\\ 
+    \acr{gid}   & '' &\textsl{group-ID reale} 
+                & indica il gruppo principale dell'utente che ha lanciato 
+                  il programma \\ 
+    \hline
+    \acr{euid}  & \textit{effective} &\textsl{user-ID effettivo} 
+                & indica l'utente usato nel controllo di accesso \\ 
+    \acr{egid}  & '' & \textsl{group-ID effettivo} 
+                & indica il gruppo usato nel controllo di accesso \\ 
+    --          & -- & \textsl{group-ID supplementari} 
+                & indicano gli ulteriori gruppi cui l'utente appartiene \\ 
+    \hline
+    --          & \textit{saved} & \textsl{user-ID salvato} 
+                & è una copia dell'\acr{euid} iniziale\\ 
+    --          & '' & \textsl{group-ID salvato} 
+                & è una copia dell'\acr{egid} iniziale \\ 
+    \hline
+    \acr{fsuid} & \textit{filesystem} &\textsl{user-ID di filesystem} 
+                & indica l'utente effettivo per l'accesso al filesystem \\ 
+    \acr{fsgid} & '' & \textsl{group-ID di filesystem} 
+                & indica il gruppo effettivo per l'accesso al filesystem  \\ 
+    \hline
+  \end{tabular}
+  \caption{Identificatori di utente e gruppo associati a ciascun processo con
+    indicazione dei suffissi usati dalle varie funzioni di manipolazione.}
+  \label{tab:proc_uid_gid}
+\end{table}
+
+Al primo gruppo appartengono l'\textsl{user-ID reale} ed il \textsl{group-ID
+  reale}: questi vengono impostati al login ai valori corrispondenti
+all'utente con cui si accede al sistema (e relativo gruppo principale).
+Servono per l'identificazione dell'utente e normalmente non vengono mai
+cambiati. In realtà vedremo (in sez.~\ref{sec:proc_setuid}) che è possibile
+modificarli, ma solo ad un processo che abbia i privilegi di amministratore;
+questa possibilità è usata proprio dal programma \cmd{login} che, una volta
+completata la procedura di autenticazione, lancia una shell per la quale
+imposta questi identificatori ai valori corrispondenti all'utente che entra
+nel sistema.
+
+Al secondo gruppo appartengono lo \textsl{user-ID effettivo} ed il
+\textsl{group-ID effettivo} (a cui si aggiungono gli eventuali \textsl{group-ID
+  supplementari} dei gruppi dei quali l'utente fa parte).  Questi sono invece
+gli identificatori usati nelle verifiche dei permessi del processo e per il
+controllo di accesso ai file (argomento affrontato in dettaglio in
+sez.~\ref{sec:file_perm_overview}).
+
+Questi identificatori normalmente sono identici ai corrispondenti del gruppo
+\textit{real} tranne nel caso in cui, come accennato in
+sez.~\ref{sec:proc_exec}, il programma che si è posto in esecuzione abbia i bit
+\acr{suid} o \acr{sgid} impostati (il significato di questi bit è affrontato
+in dettaglio in sez.~\ref{sec:file_suid_sgid}). In questo caso essi saranno
+impostati all'utente e al gruppo proprietari del file. Questo consente, per
+programmi in cui ci sia necessità, di dare a qualunque utente normale
+privilegi o permessi di un altro (o dell'amministratore).
+
+Come nel caso del \acr{pid} e del \acr{ppid}, anche tutti questi
+identificatori possono essere letti attraverso le rispettive funzioni:
+\funcd{getuid}, \funcd{geteuid}, \funcd{getgid} e \funcd{getegid}, i loro
+prototipi sono:
+\begin{functions}
+  \headdecl{unistd.h}
+  \headdecl{sys/types.h}  
+  \funcdecl{uid\_t getuid(void)} Restituisce l'\textsl{user-ID reale} del
+  processo corrente.
+
+  \funcdecl{uid\_t geteuid(void)} Restituisce l'\textsl{user-ID effettivo} del
+  processo corrente.
+
+  \funcdecl{gid\_t getgid(void)} Restituisce il \textsl{group-ID reale} del
+  processo corrente.
+  
+  \funcdecl{gid\_t getegid(void)} Restituisce il \textsl{group-ID effettivo}
+  del processo corrente.
+  
+  \bodydesc{Queste funzioni non riportano condizioni di errore.}
+\end{functions}
+
+In generale l'uso di privilegi superiori deve essere limitato il più
+possibile, per evitare abusi e problemi di sicurezza, per questo occorre anche
+un meccanismo che consenta ad un programma di rilasciare gli eventuali
+maggiori privilegi necessari, una volta che si siano effettuate le operazioni
+per i quali erano richiesti, e a poterli eventualmente recuperare in caso
+servano di nuovo.
+
+Questo in Linux viene fatto usando altri due gruppi di identificatori, il
+\textit{saved} ed il \textit{filesystem}. 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 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
+migliorare la sicurezza con NFS.
+
+L'\textsl{user-ID salvato} ed il \textsl{group-ID salvato} sono copie
+dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo} del processo
+padre, e vengono impostati dalla funzione \func{exec} all'avvio del processo,
+come copie dell'\textsl{user-ID effettivo} e del \textsl{group-ID effettivo}
+dopo che questi sono stati impostati tenendo conto di eventuali \acr{suid} o
+\acr{sgid}.  Essi quindi consentono di tenere traccia di quale fossero utente
+e gruppo effettivi all'inizio dell'esecuzione di un nuovo programma.
+
+L'\textsl{user-ID di filesystem} e il \textsl{group-ID di filesystem} sono
+un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS
+(torneremo sull'argomento in sez.~\ref{sec:proc_setuid}). Essi sono una
+replica dei corrispondenti identificatori del gruppo \textit{effective}, ai
+quali si sostituiscono per tutte le operazioni di verifica dei permessi
+relativi ai file (trattate in sez.~\ref{sec:file_perm_overview}).  Ogni
+cambiamento effettuato sugli identificatori effettivi viene automaticamente
+riportato su di essi, per cui in condizioni normali si può tranquillamente
+ignorarne l'esistenza, in quanto saranno del tutto equivalenti ai precedenti.
+
+
+\subsection{Le funzioni di gestione degli identificatori dei processi}
+\label{sec:proc_setuid}
+
+Le due funzioni più comuni che vengono usate per cambiare identità (cioè
+utente e gruppo di appartenenza) ad un processo sono rispettivamente
+\funcd{setuid} e \funcd{setgid}; come accennato in
+sez.~\ref{sec:proc_access_id} in Linux esse seguono la semantica POSIX che
+prevede l'esistenza dell'\textit{user-ID salvato} e del \textit{group-ID
+  salvato}; i loro prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int setuid(uid\_t uid)} Imposta l'\textsl{user-ID} del processo
+corrente.
+
+\funcdecl{int setgid(gid\_t gid)} Imposta il \textsl{group-ID} del processo
+corrente.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+  di fallimento: l'unico errore possibile è \errval{EPERM}.}
+\end{functions}
+
+Il funzionamento di queste due funzioni è analogo, per cui considereremo solo
+la prima; la seconda si comporta esattamente allo stesso modo facendo
+riferimento al \textsl{group-ID} invece che all'\textsl{user-ID}.  Gli
+eventuali \textsl{group-ID supplementari} non vengono modificati.
+
+L'effetto della chiamata è diverso a seconda dei privilegi del processo; se
+l'\textsl{user-ID effettivo} è zero (cioè è quello dell'amministratore di
+sistema) allora tutti gli identificatori (\textit{real}, \textit{effective} e
+\textit{saved}) vengono impostati al valore specificato da \param{uid},
+altrimenti viene impostato solo l'\textsl{user-ID effettivo}, e soltanto se il
+valore specificato corrisponde o all'\textsl{user-ID reale} o
+all'\textsl{user-ID salvato}. Negli altri casi viene segnalato un errore (con
+\errcode{EPERM}).
+
+Come accennato l'uso principale di queste funzioni è quello di poter
+consentire ad un programma con i bit \acr{suid} o \acr{sgid} impostati (vedi
+sez.~\ref{sec:file_suid_sgid}) di riportare l'\textsl{user-ID effettivo} 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 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
+falsificare la registrazione. Per questo motivo questo file (e l'analogo
+\file{/var/log/wtmp} su cui vengono registrati login e logout) appartengono ad
+un gruppo dedicato (\acr{utmp}) ed i programmi che devono accedervi (ad
+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} impostato.
+
+Quando uno di questi programmi (ad esempio \cmd{xterm}) viene lanciato, la
+situazione degli identificatori è la seguente:
+\begin{eqnarray*}
+  \label{eq:1}
+  \textsl{group-ID reale}      &=& \textrm{\acr{gid} (del chiamante)} \\
+  \textsl{group-ID effettivo}  &=& \textrm{\acr{utmp}} \\
+  \textsl{group-ID salvato}    &=& \textrm{\acr{utmp}}
+\end{eqnarray*}
+in questo modo, dato che il \textsl{group-ID effettivo} è quello giusto, il
+programma può accedere a \file{/var/log/utmp} in scrittura ed aggiornarlo. A
+questo punto il programma può eseguire una \code{setgid(getgid())} per
+impostare il \textsl{group-ID effettivo} a quello dell'utente (e dato che il
+\textsl{group-ID reale} corrisponde la funzione avrà successo), in questo modo
+non sarà possibile lanciare dal terminale programmi che modificano detto file,
+in tal caso infatti la situazione degli identificatori sarebbe:
+\begin{eqnarray*}
+  \label{eq:2}
+  \textsl{group-ID reale}      &=& \textrm{\acr{gid} (invariato)}  \\
+  \textsl{group-ID effettivo}  &=& \textrm{\acr{gid}} \\
+  \textsl{group-ID salvato}    &=& \textrm{\acr{utmp} (invariato)}
+\end{eqnarray*}
+e ogni processo lanciato dal terminale avrebbe comunque \acr{gid} come
+\textsl{group-ID effettivo}. 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 precedente \func{getegid}), dato che
+in questo caso il valore richiesto corrisponde al \textsl{group-ID salvato} la
+funzione avrà successo e riporterà la situazione a:
+\begin{eqnarray*}
+  \label{eq:3}
+  \textsl{group-ID reale}      &=& \textrm{\acr{gid} (invariato)}  \\
+  \textsl{group-ID effettivo}  &=& \textrm{\acr{utmp}} \\
+  \textsl{group-ID salvato}    &=& \textrm{\acr{utmp} (invariato)}
+\end{eqnarray*}
+consentendo l'accesso a \file{/var/log/utmp}.
+
+Occorre però tenere conto che tutto questo non è possibile con un processo con
+i privilegi di amministratore, in tal caso infatti l'esecuzione di una
+\func{setuid} comporta il cambiamento di tutti gli identificatori associati al
+processo, rendendo impossibile riguadagnare i privilegi di amministratore.
+Questo comportamento è corretto per l'uso che ne fa \cmd{login} una volta che
+crea una nuova shell per l'utente; ma quando si vuole cambiare soltanto
+l'\textsl{user-ID effettivo} del processo per cedere i privilegi occorre
+ricorrere ad altre funzioni.
+
+Le due funzioni \funcd{setreuid} e \funcd{setregid} derivano da BSD che, non
+supportando\footnote{almeno fino alla versione 4.3+BSD TODO, FIXME verificare
+  e aggiornare la nota.} gli identificatori del gruppo \textit{saved}, le usa
+per poter scambiare fra di loro \textit{effective} e \textit{real}. I
+rispettivi prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Imposta l'\textsl{user-ID
+  reale} e l'\textsl{user-ID effettivo} del processo corrente ai valori
+specificati da \param{ruid} e \param{euid}.
+  
+\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Imposta il \textsl{group-ID
+  reale} ed il \textsl{group-ID effettivo} del processo corrente ai valori
+specificati da \param{rgid} e \param{egid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+  di fallimento: l'unico errore possibile è \errval{EPERM}.}
+\end{functions}
+
+La due funzioni sono analoghe ed il loro comportamento è identico; quanto
+detto per la prima riguardo l'user-ID, si applica immediatamente alla seconda
+per il group-ID. I processi non privilegiati possono impostare solo i valori
+del loro user-ID effettivo o reale; valori diversi comportano il fallimento
+della chiamata; l'amministratore invece può specificare un valore qualunque.
+Specificando un argomento di valore -1 l'identificatore corrispondente verrà
+lasciato inalterato.
+
+Con queste funzioni si possono scambiare fra loro gli user-ID reale e
+effettivo, e pertanto è possibile implementare un comportamento simile a
+quello visto in precedenza per \func{setgid}, cedendo i privilegi con un primo
+scambio, e recuperandoli, eseguito il lavoro non privilegiato, con un secondo
+scambio.
+
+In questo caso però occorre porre molta attenzione quando si creano nuovi
+processi nella fase intermedia in cui si sono scambiati gli identificatori, in
+questo caso infatti essi avranno un user-ID reale privilegiato, che dovrà
+essere esplicitamente eliminato prima di porre in esecuzione un nuovo
+programma (occorrerà cioè eseguire un'altra chiamata dopo la \func{fork} e
+prima della \func{exec} per uniformare l'user-ID reale a quello effettivo) in
+caso contrario il nuovo programma potrebbe a sua volta effettuare uno scambio
+e riottenere privilegi non previsti.
+
+Lo stesso problema di propagazione dei privilegi ad eventuali processi figli
+si pone per l'user-ID salvato: questa funzione deriva da un'implementazione che
+non ne prevede la presenza, e quindi non è possibile usarla per correggere la
+situazione come nel caso precedente. Per questo motivo in Linux tutte le volte
+che si imposta un qualunque valore diverso da quello dall'user-ID reale
+corrente, l'user-ID salvato viene automaticamente uniformato al valore
+dell'user-ID effettivo.
+
+Altre due funzioni, \funcd{seteuid} e \funcd{setegid}, sono un'estensione
+dello standard POSIX.1, ma sono comunque supportate dalla maggior parte degli
+Unix; esse vengono usate per cambiare gli identificatori del gruppo
+\textit{effective} ed i loro prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int seteuid(uid\_t uid)} Imposta l'user-ID effettivo del processo
+corrente a \param{uid}.
+
+\funcdecl{int setegid(gid\_t gid)} Imposta il group-ID effettivo del processo
+corrente a \param{gid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+  di fallimento: l'unico errore è \errval{EPERM}.}
+\end{functions}
+
+Come per le precedenti le due funzioni sono identiche, per cui tratteremo solo
+la prima. Gli utenti normali possono impostare l'user-ID effettivo solo al
+valore dell'user-ID reale o dell'user-ID salvato, l'amministratore può
+specificare qualunque valore. Queste funzioni sono usate per permettere
+all'amministratore di impostare solo l'user-ID effettivo, dato che l'uso
+normale di \func{setuid} comporta l'impostazione di tutti gli identificatori.
+
+Le due funzioni \funcd{setresuid} e \funcd{setresgid} sono invece
+un'estensione introdotta in Linux,\footnote{per essere precisi a partire dal
+  kernel 2.1.44.}  e permettono un completo controllo su tutti e tre i gruppi
+di identificatori (\textit{real}, \textit{effective} e \textit{saved}), i loro
+prototipi sono:
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Imposta
+l'user-ID reale, l'user-ID effettivo e l'user-ID salvato del processo corrente
+ai valori specificati rispettivamente da \param{ruid}, \param{euid} e
+\param{suid}.
+  
+\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Imposta il
+group-ID reale, il group-ID effettivo ed il group-ID salvato del processo
+corrente ai valori specificati rispettivamente da \param{rgid}, \param{egid} e
+\param{sgid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+  di fallimento: l'unico errore è \errval{EPERM}.}
+\end{functions}
+
+Le due funzioni sono identiche, quanto detto per la prima riguardo gli user-ID
+si applica alla seconda per i group-ID. I processi non privilegiati possono
+cambiare uno qualunque degli user-ID solo ad un valore corrispondente o
+all'user-ID reale, o a quello effettivo o a quello salvato, l'amministratore
+può specificare i valori che vuole; un valore di -1 per un qualunque argomento
+lascia inalterato l'identificatore corrispondente.
 
-Per questo motivo in generale tutti i processi hanno almeno due gruppi di
-identificatori, chiamati rispettivamente \textsl{reale} e \textsl{effettivo}.
-Al primo gruppo appartengono il \textit{real user ID} e il \textit{real group
-  ID}, che vengono settati al login ai valori corrispondenti all'utente con
-cui si accede al sistema (e relativo gruppo di default), questi normalmente
-non vengono mai cambiati.
+Per queste funzioni esistono anche due controparti che permettono di leggere
+in blocco i vari identificatori: \funcd{getresuid} e \funcd{getresgid}; i loro
+prototipi sono: 
+\begin{functions}
+\headdecl{unistd.h}
+\headdecl{sys/types.h}
+
+\funcdecl{int getresuid(uid\_t *ruid, uid\_t *euid, uid\_t *suid)} Legge
+l'user-ID reale, l'user-ID effettivo e l'user-ID salvato del processo corrente.
+  
+\funcdecl{int getresgid(gid\_t *rgid, gid\_t *egid, gid\_t *sgid)} Legge il
+group-ID reale, il group-ID effettivo e il group-ID salvato del processo
+corrente.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso di
+  fallimento: l'unico errore possibile è \errval{EFAULT} se gli indirizzi delle
+  variabili di ritorno non sono validi.}
+\end{functions}
 
-Al secondo gruppo appartengono l'\textit{effective user ID} e
-l'\textit{effective group ID} che sono gli identificatori usati nella
-verifiche dei permessi, (ad esempio, come vedremo in
-\secref{sec:file_perm_overview} vengono usati nel controllo di accesso ai
-file). 
+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
+\index{\textit{value~result~argument}}\textit{value result argument}). Si noti
+che queste funzioni sono le uniche in grado di leggere gli identificatori del
+gruppo \textit{saved}.
+
+
+Infine le funzioni \func{setfsuid} e \func{setfsgid} servono per impostare gli
+identificatori del gruppo \textit{filesystem} che sono usati da Linux per il
+controllo dell'accesso ai file.  Come già accennato in
+sez.~\ref{sec:proc_access_id} Linux definisce questo ulteriore gruppo di
+identificatori, che in circostanze normali sono assolutamente equivalenti a
+quelli del gruppo \textit{effective}, dato che ogni cambiamento di questi
+ultimi viene immediatamente riportato su di essi.
+
+C'è un solo caso in cui si ha necessità di introdurre una differenza fra gli
+identificatori dei gruppi \textit{effective} e \textit{filesystem}, ed è per
+ovviare ad un problema di sicurezza che si presenta quando si deve
+implementare un server NFS. 
+
+Il server NFS infatti deve poter cambiare l'identificatore con cui accede ai
+file per assumere l'identità del singolo utente remoto, ma se questo viene
+fatto cambiando l'user-ID effettivo o l'user-ID reale il server si espone alla
+ricezione di eventuali segnali ostili da parte dell'utente di cui ha
+temporaneamente assunto l'identità.  Cambiando solo l'user-ID di filesystem si
+ottengono i privilegi necessari per accedere ai file, mantenendo quelli
+originari per quanto riguarda tutti gli altri controlli di accesso, così che
+l'utente non possa inviare segnali al server NFS.
+
+Le due funzioni usate per cambiare questi identificatori sono \funcd{setfsuid}
+e \funcd{setfsgid}, ovviamente sono specifiche di Linux e non devono essere
+usate se si intendono scrivere programmi portabili; i loro prototipi sono:
+\begin{functions}
+\headdecl{sys/fsuid.h}
+
+\funcdecl{int setfsuid(uid\_t fsuid)} Imposta l'user-ID di filesystem del
+processo corrente a \param{fsuid}.
+
+\funcdecl{int setfsgid(gid\_t fsgid)} Imposta il group-ID di filesystem del
+processo corrente a \param{fsgid}.
+
+\bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
+  di fallimento: l'unico errore possibile è \errval{EPERM}.}
+\end{functions}
+\noindent queste funzioni hanno successo solo se il processo chiamante ha i
+privilegi di amministratore o, per gli altri utenti, se il valore specificato
+coincide con uno dei di quelli del gruppo \textit{real}, \textit{effective} o
+\textit{saved}.
+
+
+\subsection{Le funzioni per la gestione dei gruppi associati a un processo}
+\label{sec:proc_setgroups}
+
+Le ultime funzioni che esamineremo sono quelle che permettono di operare sui
+gruppi supplementari cui un utente può appartenere. Ogni processo può avere
+almeno \const{NGROUPS\_MAX} gruppi supplementari\footnote{il numero massimo di
+  gruppi secondari può essere ottenuto con \func{sysconf} (vedi
+  sez.~\ref{sec:sys_sysconf}), leggendo il parametro
+  \texttt{\_SC\_NGROUPS\_MAX}.} 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 associati ad un
+processo è \funcd{getgroups}; questa funzione è definita nello standard
+POSIX.1, ed il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h}
+  \headdecl{unistd.h}
+  
+  \funcdecl{int getgroups(int size, gid\_t list[])} 
+  
+  Legge gli identificatori dei gruppi supplementari.
+  
+  \bodydesc{La funzione restituisce il numero di gruppi letti in caso di
+    successo e -1 in caso di fallimento, nel qual caso \var{errno} assumerà
+    i valori: 
+    \begin{errlist}
+    \item[\errcode{EFAULT}] \param{list} non ha un indirizzo valido.
+    \item[\errcode{EINVAL}] il valore di \param{size} è diverso da zero ma
+      minore del numero di gruppi supplementari del processo.
+    \end{errlist}}
+\end{functions}
 
-Questi normalmente sono identici ai corrispondenti del gruppo reale tranne nel
-caso in cui (come abbiamo accennato in \secref{sec:proc_exec}) il programma
-che si è posto in esecuzione abbia i bit \acr{suid} o \acr{sgid} settati (su
-questo torneremo in maggior dettagli in \secref{sec:file_suid_sgid}) nel qual
-caso essi saranno settati all'utente e al gruppo proprietari del file.
+La funzione legge gli identificatori dei gruppi supplementari del processo sul
+vettore \param{list} di dimensione \param{size}. Non è specificato se la
+funzione inserisca o meno nella lista il group-ID effettivo del processo. Se si
+specifica un valore di \param{size} uguale a 0 \param{list} non viene
+modificato, ma si ottiene il numero di gruppi supplementari.
 
+Una seconda funzione, \funcd{getgrouplist}, può invece essere usata per
+ottenere tutti i gruppi a cui appartiene un certo utente; il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h} 
+  \headdecl{grp.h}
+  
+  \funcdecl{int getgrouplist(const char *user, gid\_t group, gid\_t *groups,
+    int *ngroups)} Legge i gruppi supplementari.
+  
+  \bodydesc{La funzione legge fino ad un massimo di \param{ngroups} valori,
+    restituisce 0 in caso di successo e -1 in caso di fallimento.}
+\end{functions}
 
+La funzione legge i gruppi supplementari dell'utente specificato da
+\param{user}, eseguendo una scansione del database dei gruppi (si veda
+sez.~\ref{sec:sys_user_group}). Ritorna poi 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, passando indietro il numero dei gruppi trovati.
 
+Per impostare i gruppi supplementari di un processo ci sono due funzioni, che
+possono essere usate solo se si hanno i privilegi di amministratore. La prima
+delle due è \funcd{setgroups}, ed il suo prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h}
+  \headdecl{grp.h}
+  
+  \funcdecl{int setgroups(size\_t size, gid\_t *list)} 
+  
+  Imposta i gruppi supplementari del processo.
+
+  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+    fallimento, nel qual caso \var{errno} assumerà i valori:
+    \begin{errlist}
+    \item[\errcode{EFAULT}] \param{list} non ha un indirizzo valido.
+    \item[\errcode{EPERM}] il processo non ha i privilegi di amministratore.
+    \item[\errcode{EINVAL}] il valore di \param{size} è maggiore del valore
+    massimo consentito.
+    \end{errlist}}
+\end{functions}
 
-Oltre a questi Linux, seguendo 
+La funzione imposta i gruppi supplementari del processo corrente ai valori
+specificati nel vettore passato con l'argomento \param{list}, di dimensioni
+date dall'argomento \param{size}. Il numero massimo di gruppi supplementari è
+un parametro di sistema, che può essere ricavato con le modalità spiegate in
+sez.~\ref{sec:sys_characteristics}.
 
+Se invece si vogliono impostare i gruppi supplementari del processo a quelli di
+un utente specifico, si può usare \funcd{initgroups} il cui prototipo è:
+\begin{functions}
+  \headdecl{sys/types.h}
+  \headdecl{grp.h}
 
-Linux inoltre, per poter rilasciare eventuali privilegi addizionali avuti con
-l'esecuzione di un programma 
+  \funcdecl{int initgroups(const char *user, gid\_t group)} 
+  
+  Inizializza la lista dei gruppi supplementari.
+  
+  \bodydesc{La funzione restituisce 0 in caso di successo e -1 in caso di
+    fallimento, nel qual caso \var{errno} assumerà gli stessi valori di
+    \func{setgroups} più \errval{ENOMEM} quando non c'è memoria sufficiente
+    per allocare lo spazio per informazioni dei gruppi.}
+\end{functions}
 
+La funzione esegue la scansione del database dei gruppi (usualmente
+\file{/etc/groups}) cercando i gruppi di cui è membro l'utente \param{user}
+con cui costruisce una lista di gruppi supplementari, a cui aggiunge anche
+\param{group}, infine imposta questa lista per il processo corrente 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 quando si definisce \macro{\_POSIX\_SOURCE} o si
+compila con il flag \cmd{-ansi}, è pertanto meglio evitarle se si vuole
+scrivere codice portabile.
+
+
+%\subsection{La gestione delle capabilities}
+%\label{sec:proc_capabilities}
+
+
+
+
+\section{La gestione della priorità di esecuzione}
+\label{sec:proc_priority}
+
+In questa sezione tratteremo più approfonditamente i meccanismi con il quale
+lo \textit{scheduler}\index{\textit{scheduler}} 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 generale essa dipende in maniera
+essenziale anche dal tipo di utilizzo che deve essere fatto del sistema, per
+cui non esiste un meccanismo che sia valido per tutti gli usi.
+
+La caratteristica specifica di un sistema multitasking come Linux è quella del
+cosiddetto \textit{prehemptive multitasking}: questo significa che al
+contrario di altri sistemi (che usano invece il cosiddetto \textit{cooperative
+  multitasking}) non sono i singoli processi, ma il kernel stesso a decidere
+quando la CPU deve essere passata ad un altro processo. Come accennato in
+sez.~\ref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
+apposita del kernel, lo \textit{scheduler}\index{\textit{scheduler}}, il cui
+scopo è quello di distribuire al meglio il tempo di CPU fra i vari processi.
+
+La cosa è resa ancora più complicata dal fatto che con le architetture
+multi-processore si deve anche scegliere 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 effettuare la migliore scelta fra le diverse CPU non è
+  banale.}  Tutto questo comunque appartiene alle sottigliezze
+dell'implementazione del kernel; 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), le politiche di scheduling riguardano
+semplicemente l'allocazione della risorsa \textsl{tempo di esecuzione}, la cui
+assegnazione sarà governata dai meccanismi di scelta delle priorità che
+restano gli stessi indipendentemente dal numero di processori.
+
+Si tenga conto poi che i processi non devono solo eseguire del codice: ad
+esempio molto spesso saranno impegnati in operazioni di I/O, o potranno
+venire bloccati da un comando dal terminale, o sospesi per un certo periodo di
+tempo.  In tutti questi casi la CPU diventa disponibile ed è compito dello
+kernel provvedere a mettere in esecuzione un altro processo.
+
+Tutte queste possibilità sono caratterizzate da un diverso \textsl{stato} del
+processo, in Linux un processo può trovarsi in uno degli stati riportati in
+tab.~\ref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
+\textit{runnable} concorrono per l'esecuzione. Questo vuol dire che, qualunque
+sia la sua priorità, un processo non potrà mai essere messo in esecuzione
+fintanto che esso si trova in uno qualunque degli altri stati.
 
 \begin{table}[htb]
   \footnotesize
   \centering
-  \begin{tabular}[c]{|c|l|p{8cm}|}
+  \begin{tabular}[c]{|p{2.8cm}|c|p{10cm}|}
     \hline
-    \textbf{Sigla} & \textbf{Significato} & \textbf{Utilizzo} \\ 
+    \textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\
     \hline
     \hline
-    \acr{ruid} & \textit{real user id} & indica l'utente reale che ha lanciato
-    il programma\\ 
-    \acr{rgid} & \textit{real group id} & indica il gruppo reale dell'utente 
-    che ha lanciato il programma \\ 
-    \acr{euid} & \textit{effective user id} & indica l'utente effettivo usato
-    dal programma \\ 
-    \acr{egid} & \textit{effective group id} & indica il gruppo effettivo usato
-    dal programma \\ 
-               & \textit{supplementary group id} & indica i gruppi cui
-    l'utente appartiene  \\ 
-    \acr{suid} & \textit{saved user id} & indica l'utente  \\ 
-    \acr{sgid} & \textit{saved group id} & indica il gruppo  \\ 
-    \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per
-    il filesystem \\ 
-    \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo
-    per il filesystem  \\ 
+    \textbf{Runnable}& \texttt{R} & Il processo è in esecuzione o è pronto ad
+                                    essere eseguito (cioè è in attesa che gli
+                                    venga assegnata la CPU). \\
+    \textbf{Sleep}   & \texttt{S} & Il processo  è in attesa di un
+                                    risposta dal sistema, ma può essere 
+                                    interrotto da un segnale. \\
+    \textbf{Uninterrutible Sleep}& \texttt{D} & Il  processo è in
+                                    attesa di un risposta dal sistema (in 
+                                    genere per I/O), e non può essere
+                                    interrotto in nessuna circostanza. \\
+    \textbf{Stopped} & \texttt{T} & Il processo è stato fermato con un
+                                    \const{SIGSTOP}, o è tracciato.\\
+    \textbf{Zombie}\index{zombie} & \texttt{Z} & Il processo è terminato ma il
+                                    suo stato di terminazione non è ancora
+                                    stato letto dal padre. \\
     \hline
   \end{tabular}
-  \caption{Identificatori di utente e gruppo associati a ciascun processo.}
-  \label{tab:proc_uid_gid}
+  \caption{Elenco dei possibili stati di un processo in Linux, nella colonna
+    \texttt{STAT} si è riportata la corrispondente lettera usata dal comando 
+    \cmd{ps} nell'omonimo campo.}
+  \label{tab:proc_proc_states}
 \end{table}
 
-Il \textit{real user id} e il \textit{real group id} indicano l'utente che ha
-lanciato il processo, e vengono settati al login al valore standard di
-\acr{uid} e \acr{gid} dell'utente letti direttamente da \file{/etc/passwd}.
-
-Esso servono ad identificare l'utente che ha lanciato il processo e non
-vengono mai cambiati nella creazione di nuovi processi restando sempre gli
-stessi per tutti i processi avviati in una sessione. In realtà vedremo che è
-possibile possibile modificarli (in \secref{sec:proc_setuid}), ma solo ad un
-processo che abbia i privilegi di amministratore; questa possibilità è usata
-ad esempio da \cmd{login} che una volta completata la procedura di
-autenticazione lancia una shell per la quale setta questi identificatori ai
-valori corrispondenti all'utente che entra nel sistema.
-
-L'\textit{effective user id}, l'\textit{effective group id} e gli eventuali
-\textit{supplementary group id} sono invece gli identificatori usati per il
-controllo di accesso ai file (secondo quanto descritto in dettaglio in
-\secref{sec:file_perm_overview}). Normalmente essi sono uguali al \textit{real
-  user id} e al \textit{real group id}, a meno che il file posto in esecuzione
-non abbia o il bit \acr{suid} o il bit \acr{sgid} settato, in questo caso alla
-la funzione \func{exec} (vedi \secref{}) li setta rispettivamente ai valori
-dell'\acr{uid} e del \acr{gid} cui appartiene il file.
-
-Il \textit{saved user id} e il \textit{saved group id} sono copie
-dell'\textit{effective user id} e dell'\textit{effective group id} del
-processo padre, e vengono settati dalla funzione \func{exec} all'avvio del
-processo, prima che \textit{effective user id} e \textit{effective group id}
-vengano modificati per tener conto di eventuali \acr{suid} o \acr{sgid}, essi
-quindi consentono di tenere traccia di quale fossero l'utente originale.
-
-
-\subsection{Le funzioni \texttt{setuid} e \texttt{setgid}}
-\label{sec:proc_setuid}
+Si deve quindi tenere presente che l'utilizzo della CPU è soltanto una delle
+risorse che sono necessarie per l'esecuzione di un programma, e a seconda
+dello scopo del programma non è detto neanche che sia la più importante (molti
+programmi dipendono in maniera molto più critica dall'I/O). Per questo motivo
+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
+sez.~\ref{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 un tempo ben determinato; 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.
+Ovviamente questo avviene solo per i processi che sono pronti per essere
+eseguiti (cioè nello stato \textit{runnable}).  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
+sez.~\ref{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 con il meccanismo tradizionale della
+priorità dinamica. In Linux 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 esigenze specifiche, l'unico meccanismo di
+scheduling con il quale si avrà a che fare è quello tradizionale, che prevede
+solo priorità dinamiche. È 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é varia nel corso dell'esecuzione di un processo. Oltre a
+questo la priorità dinamica determina quanto a lungo un processo continuerà ad
+essere eseguito, e quando un processo potrà subentrare ad un altro
+nell'esecuzione.
+
+Il meccanismo usato da Linux è piuttosto semplice,\footnote{in realtà nella
+  serie 2.6.x lo \textit{scheduler} è stato riscritto da zero e può usare
+  diversi algoritmi, selezionabili sia in fase di compilazione, che, nelle
+  versioni più recenti, all'avvio (addirittura è stato ideato un sistema
+  modulare che permette di cambiare lo scheduler al volo, che comunque non è
+  incluso nel kernel ufficiale).} ad ogni processo è assegnata una
+\textit{time-slice}, cioè un intervallo di tempo (letteralmente una fetta) per
+il quale esso deve essere eseguito. Il valore della \textit{time-slice} è
+controllato dalla cosiddetta \textit{nice} (o \textit{niceness}) del processo.
+Essa è contenuta nel campo \var{nice} di \struct{task\_struct}; tutti i
+processi vengono creati con lo stesso valore, ed essa specifica il valore
+della durata iniziale della \textit{time-slice} che viene assegnato ad un
+altro campo della struttura (\var{counter}) quando il processo viene eseguito
+per la prima volta e diminuito progressivamente ad ogni interruzione del
+timer.
+
+Durante la sua esecuzione lo scheduler\index{\textit{scheduler}} scandisce la
+coda dei processi in stato \textit{runnable} associando, in base al valore di
+\var{counter}, un peso ad ogni processo in attesa di esecuzione,\footnote{il
+  calcolo del peso in realtà è un po' più complicato, ad esempio nei sistemi
+  multiprocessore viene favorito un processo eseguito sulla stessa CPU, e a
+  parità del valore di \var{counter} viene favorito chi ha una priorità più
+  elevata.} chi ha il peso più alto verrà posto in esecuzione, ed il
+precedente processo sarà spostato in fondo alla coda.  Dato che ad ogni
+interruzione del timer il valore di \var{counter} del processo corrente viene
+diminuito, questo assicura che anche i processi con priorità più bassa
+verranno messi in esecuzione.
+
+La priorità di un processo è così controllata attraverso il valore di
+\var{nice}, che stabilisce la durata della \textit{time-slice}; per il
+meccanismo appena descritto infatti un valore più lungo assicura una maggiore
+attribuzione di CPU.  L'origine del nome di questo parametro sta nel fatto che
+generalmente questo viene usato per diminuire la priorità di un processo, come
+misura di cortesia nei confronti degli altri.  I processi infatti vengono
+creati dal sistema con lo stesso valore di \var{nice} (nullo) e nessuno è
+privilegiato rispetto agli altri; il valore può essere modificato solo
+attraverso la funzione \funcd{nice}, il cui prototipo è:
+\begin{prototype}{unistd.h}
+{int nice(int inc)}
+  Aumenta il valore di \var{nice} per il processo corrente.
+  
+  \bodydesc{La funzione ritorna zero in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} può assumere i valori:
+  \begin{errlist}
+  \item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha
+    specificato un valore di \param{inc} negativo.
+  \end{errlist}}
+\end{prototype}
+
+L'argomento \param{inc} indica l'incremento del valore di \var{nice}:
+quest'ultimo può assumere valori compresi fra \const{PRIO\_MIN} e
+\const{PRIO\_MAX} (che nel caso di Linux sono $-19$ e $20$), ma per
+\param{inc} si può specificare un valore qualunque, positivo o negativo, ed il
+sistema provvederà a troncare il risultato nell'intervallo consentito. Valori
+positivi comportano maggiore \textit{cortesia} e cioè una diminuzione della
+priorità, ogni utente può solo innalzare il valore di un suo processo. Solo
+l'amministratore può specificare valori negativi che permettono di aumentare
+la priorità di un processo.
+
+In SUSv2 la funzione ritorna il nuovo valore di \var{nice}; Linux non segue
+questa convenzione, e per leggere il nuovo valore occorre invece usare la
+funzione \funcd{getpriority}, derivata da BSD, il cui prototipo è:
+\begin{prototype}{sys/resource.h}
+{int getpriority(int which, int who)}
+  
+Restituisce il valore di \var{nice} per l'insieme dei processi specificati.
+
+  \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} può assumere i valori:
+  \begin{errlist}
+  \item[\errcode{ESRCH}] non c'è nessun processo che corrisponda ai valori di
+  \param{which} e \param{who}.
+  \item[\errcode{EINVAL}] il valore di \param{which} non è valido.
+  \end{errlist}}
+\end{prototype}
+\noindent nelle vecchie versioni può essere necessario includere anche
+\file{<sys/time.h>}, questo non è più necessario con versioni recenti delle
+librerie, ma è comunque utile per portabilità.
+
+La funzione permette, a seconda del valore di \param{which}, di leggere la
+priorità di un processo, di un gruppo di processi (vedi
+sez.~\ref{sec:sess_proc_group}) o di un utente, specificando un corrispondente
+valore per \param{who} secondo la legenda di tab.~\ref{tab:proc_getpriority};
+un valore nullo di quest'ultimo indica il processo, il gruppo di processi o
+l'utente correnti.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|c|c|l|}
+    \hline
+    \param{which} & \param{who} & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{PRIO\_PROCESS} & \type{pid\_t} &  processo  \\
+    \const{PRIO\_PRGR}    & \type{pid\_t} &  process group  \\
+    \const{PRIO\_USER}    & \type{uid\_t} &  utente \\
+    \hline
+  \end{tabular}
+  \caption{Legenda del valore dell'argomento \param{which} e del tipo
+    dell'argomento \param{who} delle funzioni \func{getpriority} e
+    \func{setpriority} per le tre possibili scelte.}
+  \label{tab:proc_getpriority}
+\end{table}
+
+La funzione restituisce la priorità più alta (cioè il valore più basso) fra
+quelle dei processi specificati; dato che -1 è un valore possibile, per poter
+rilevare una condizione di errore è necessario cancellare sempre \var{errno}
+prima della chiamata alla funzione, per verificare che essa resti uguale a
+zero.  
+
+Analoga a \func{getpriority} la funzione \funcd{setpriority} permette di
+impostare la priorità di uno o più processi; il suo prototipo è:
+\begin{prototype}{sys/resource.h}
+{int setpriority(int which, int who, int prio)}  
+  Imposta la priorità per l'insieme dei processi specificati.
+
+  \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso di
+    errore, nel qual caso \var{errno} può assumere i valori:
+  \begin{errlist}
+  \item[\errcode{ESRCH}] non c'è nessun processo che corrisponda ai valori di
+  \param{which} e \param{who}.
+  \item[\errcode{EINVAL}] il valore di \param{which} non è valido.
+  \item[\errcode{EPERM}] un processo senza i privilegi di amministratore ha
+    specificato un valore di \param{inc} negativo.
+  \item[\errcode{EACCES}] un processo senza i privilegi di amministratore ha
+    cercato di modificare la priorità di un processo di un altro utente.
+  \end{errlist}}
+\end{prototype}
+
+La funzione imposta la priorità al valore specificato da \param{prio} per
+tutti i processi indicati dagli argomenti \param{which} e \param{who}.  La
+gestione dei permessi dipende dalle varie implementazioni; in Linux, secondo
+le specifiche dello standard SUSv3, e come avviene per tutti i sistemi che
+derivano da SysV, è richiesto che l'user-ID reale o effettivo del processo
+chiamante corrispondano al real user-ID (e solo quello) del processo di cui si
+vuole cambiare la priorità; per i sistemi derivati da BSD invece (SunOS,
+Ultrix, *BSD) la corrispondenza può essere anche con l'user-ID effettivo.
+
+
+
+\subsection{Il meccanismo di \textit{scheduling real-time}}
+\label{sec:proc_real_time}
+
+Come spiegato in sez.~\ref{sec:proc_sched} lo standard POSIX.1b ha introdotto
+le priorità assolute per permettere la gestione di processi real-time. In
+realtà nel caso di Linux non si tratta di un vero hard real-time, in quanto in
+presenza di eventuali interrupt il kernel interrompe l'esecuzione di un
+processo qualsiasi sia la sua priorità,\footnote{questo a meno che non si
+  siano installate le patch di RTLinux, RTAI o Adeos, con i quali è possibile
+  ottenere un sistema effettivamente hard real-time. In tal caso infatti gli
+  interrupt vengono intercettati dall'interfaccia real-time (o nel caso di
+  Adeos gestiti dalle code del nano-kernel), in modo da poterli controllare
+  direttamente qualora ci sia la necessità di avere un processo con priorità
+  più elevata di un \textit{interrupt handler}.} mentre con l'incorrere in un
+page fault\index{\textit{page~fault}} si possono avere ritardi non previsti.
+Se l'ultimo problema può essere aggirato attraverso l'uso delle funzioni di
+controllo della memoria virtuale (vedi sez.~\ref{sec:proc_mem_lock}), il primo
+non è superabile e può comportare ritardi non prevedibili riguardo ai tempi di
+esecuzione di qualunque processo.
+
+Occorre usare le priorità assolute con molta attenzione: se si dà ad un
+processo una priorità assoluta e questo finisce in un loop infinito, nessun
+altro processo potrà essere eseguito, ed esso sarà mantenuto in esecuzione
+permanentemente assorbendo tutta la CPU e senza nessuna possibilità di
+riottenere l'accesso al sistema. Per questo motivo è sempre opportuno, quando
+si lavora con processi che usano priorità assolute, tenere attiva una shell
+cui si sia assegnata la massima priorità assoluta, in modo da poter essere
+comunque in grado di rientrare nel sistema.
+
+Quando c'è un processo con priorità assoluta lo
+scheduler\index{\textit{scheduler}} lo metterà in esecuzione prima di ogni
+processo normale. In caso di più processi sarà eseguito per primo quello con
+priorità assoluta più alta. Quando ci sono più processi con la stessa priorità
+assoluta questi vengono tenuti in una coda e tocca al kernel decidere quale
+deve essere eseguito.  Il meccanismo con cui vengono gestiti questi processi
+dipende dalla politica di scheduling che si è scelto; lo standard ne prevede
+due:
+\begin{basedescript}{\desclabelwidth{1.2cm}\desclabelstyle{\nextlinelabel}}
+\item[\textit{FIFO}] \textit{First In First Out}. Il processo viene eseguito
+  fintanto che non cede volontariamente la CPU (con \func{sched\_yield}), si
+  blocca, finisce o viene interrotto da un processo a priorità più alta. Se il
+  processo viene interrotto da uno a priorità più alta esso resterà in cima
+  alla lista e sarà il primo ad essere eseguito quando i processi a priorità
+  più alta diverranno inattivi. Se invece lo si blocca volontariamente sarà
+  posto in coda alla lista (ed altri processi con la stessa priorità potranno
+  essere eseguiti).
+\item[\textit{RR}] \textit{Round Robin}. Il comportamento è del tutto analogo
+  a quello precedente, con la sola differenza che ciascun processo viene
+  eseguito al massimo per un certo periodo di tempo (la cosiddetta
+  \textit{time slice}) dopo di che viene automaticamente posto in fondo alla
+  coda dei processi con la stessa priorità. In questo modo si ha comunque una
+  esecuzione a turno di tutti i processi, da cui il nome della politica. Solo
+  i processi con la stessa priorità ed in stato \textit{runnable} entrano nel
+  \textsl{girotondo}.
+\end{basedescript}
+
+La funzione per impostare le politiche di scheduling (sia real-time che
+ordinarie) ed i relativi parametri è \funcd{sched\_setscheduler}; il suo
+prototipo è:
+\begin{prototype}{sched.h}
+{int sched\_setscheduler(pid\_t pid, int policy, const struct sched\_param *p)}
+  Imposta priorità e politica di scheduling.
+  
+  \bodydesc{La funzione ritorna la priorità in caso di successo e -1 in caso
+    di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+    \item[\errcode{EINVAL}] il valore di \param{policy} non esiste o il
+      relativo valore di \param{p} non è valido.
+    \item[\errcode{EPERM}] il processo non ha i privilegi per attivare la
+      politica richiesta.
+  \end{errlist}}
+\end{prototype}
+
+La funzione esegue l'impostazione per il processo specificato dall'argomento
+\param{pid}; un valore nullo esegue l'impostazione per il processo corrente.
+La politica di scheduling è specificata dall'argomento \param{policy} i cui
+possibili valori sono riportati in tab.~\ref{tab:proc_sched_policy}; un valore
+negativo per \param{policy} mantiene la politica di scheduling corrente.
+Solo un processo con i privilegi di amministratore può impostare priorità
+assolute diverse da zero o politiche \const{SCHED\_FIFO} e \const{SCHED\_RR}.
+
+\begin{table}[htb]
+  \centering
+  \footnotesize
+  \begin{tabular}[c]{|l|l|}
+    \hline
+    \textbf{Policy}  & \textbf{Significato} \\
+    \hline
+    \hline
+    \const{SCHED\_FIFO} & Scheduling real-time con politica \textit{FIFO} \\
+    \const{SCHED\_RR}   & Scheduling real-time con politica \textit{Round
+    Robin} \\
+    \const{SCHED\_OTHER}& Scheduling ordinario\\
+    \hline
+  \end{tabular}
+  \caption{Valori dell'argomento \param{policy} per la funzione
+    \func{sched\_setscheduler}.}
+  \label{tab:proc_sched_policy}
+\end{table}
+
+Il valore della priorità è passato attraverso la struttura
+\struct{sched\_param} (riportata in fig.~\ref{fig:sig_sched_param}), il cui
+solo campo attualmente definito è \var{sched\_priority}, che nel caso delle
+priorità assolute deve essere specificato nell'intervallo fra un valore
+massimo ed uno minimo, che nel caso sono rispettivamente 1 e 99; il valore
+nullo è legale, ma indica i processi normali.
+
+\begin{figure}[!bht]
+  \footnotesize \centering
+  \begin{minipage}[c]{15cm}
+    \includestruct{listati/sched_param.c}
+  \end{minipage} 
+  \normalsize 
+  \caption{La struttura \structd{sched\_param}.} 
+  \label{fig:sig_sched_param}
+\end{figure}
+
+Si tenga presente che quando si imposta una politica di scheduling real-time
+per un processo (o se ne cambia la priorità con \func{sched\_setparam}) questo
+viene messo in cima alla lista dei processi con la stessa priorità; questo
+comporta che verrà eseguito subito, interrompendo eventuali altri processi con
+la stessa priorità in quel momento in esecuzione.
+
+Lo standard POSIX.1b prevede comunque che i due valori della massima e minima
+priorità statica possano essere ottenuti, per ciascuna delle politiche di
+scheduling \textit{real-time}, tramite le due funzioni
+\funcd{sched\_get\_priority\_max} e \funcd{sched\_get\_priority\_min}, i cui
+prototipi sono:
+\begin{functions}
+  \headdecl{sched.h}
+  
+  \funcdecl{int sched\_get\_priority\_max(int policy)} Legge il valore
+  massimo della priorità statica per la politica di scheduling \param{policy}.
+
+  
+  \funcdecl{int sched\_get\_priority\_min(int policy)} Legge il valore minimo
+  della priorità statica per la politica di scheduling \param{policy}.
+  
+  \bodydesc{La funzioni ritornano il valore della priorità in caso di successo
+    e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{EINVAL}] il valore di \param{policy} non è valido.
+  \end{errlist}}
+\end{functions}
+
+
+I processi con politica di scheduling \const{SCHED\_OTHER} devono specificare
+un valore nullo (altrimenti si avrà un errore \errcode{EINVAL}), questo valore
+infatti non ha niente a che vedere con la priorità dinamica determinata dal
+valore di \var{nice}, che deve essere impostato con le funzioni viste in
+precedenza.
+
+Il kernel mantiene i processi con la stessa priorità assoluta in una lista, ed
+esegue sempre il primo della lista, mentre un nuovo processo che torna in
+stato \textit{runnable} viene sempre inserito in coda alla lista. Se la
+politica scelta è \const{SCHED\_FIFO} quando il processo viene eseguito viene
+automaticamente rimesso in coda alla lista, e la sua esecuzione continua
+fintanto che non viene bloccato da una richiesta di I/O, o non rilascia
+volontariamente la CPU (in tal caso, tornando nello stato \textit{runnable}
+sarà reinserito in coda alla lista); l'esecuzione viene ripresa subito solo
+nel caso che esso sia stato interrotto da un processo a priorità più alta.
+
+Se si intende operare solo sulla priorità assoluta di un processo si possono
+usare le funzioni \funcd{sched\_setparam} e \funcd{sched\_getparam}, i cui
+prototipi sono:
+\begin{functions}
+  \headdecl{sched.h}
+
+  \funcdecl{int sched\_setparam(pid\_t pid, const struct sched\_param *p)}
+  Imposta la priorità assoluta del processo \param{pid}.
+
+  \funcdecl{int sched\_getparam(pid\_t pid, struct sched\_param *p)}
+  Legge la priorità assoluta del processo \param{pid}.
+
+  \bodydesc{La funzione ritorna la priorità  in caso di successo
+    e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+    \item[\errcode{EINVAL}] il valore di \param{p} non ha senso per la
+      politica scelta.
+    \item[\errcode{EPERM}] il processo non ha i privilegi sufficienti per
+      eseguire l'operazione.
+  \end{errlist}}
+\end{functions}
+
+L'uso di \func{sched\_setparam} che è del tutto equivalente a
+\func{sched\_setscheduler} con \param{priority} uguale a -1. Come per
+\func{sched\_setscheduler} specificando 0 come valore di \param{pid} si opera
+sul processo corrente. La disponibilità di entrambe le funzioni può essere
+verificata controllando la macro \macro{\_POSIX\_PRIORITY\_SCHEDULING} che è
+definita nell'header \file{sched.h}. 
+
+Si tenga presente che per eseguire la funzione il processo chiamante deve
+avere un user-ID effettivo uguale all'user-ID reale o a quello effettivo del
+processo di cui vuole cambiare la priorità, oppure deve avere i privilegi di
+amministratore (con la capacità \const{CAP\_SYS\_NICE}).
+
+La priorità assoluta può essere riletta indietro dalla funzione
+\funcd{sched\_getscheduler}, il cui prototipo è:
+\begin{prototype}{sched.h}
+{int sched\_getscheduler(pid\_t pid)}
+  Legge la politica di scheduling per il processo \param{pid}.
+  
+  \bodydesc{La funzione ritorna la politica di scheduling in caso di successo
+    e -1 in caso di errore, nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+    \item[\errcode{EINVAL}] il valore di \param{pid} è negativo.
+  \end{errlist}}
+\end{prototype}
+
+La funzione restituisce il valore (secondo quanto elencato in
+tab.~\ref{tab:proc_sched_policy}) della politica di scheduling per il processo
+specificato; se \param{pid} è nullo viene restituito quello del processo
+chiamante.
+
+L'ultima funzione che permette di leggere le informazioni relative ai processi
+real-time è \funcd{sched\_rr\_get\_interval}, che permette di ottenere la
+lunghezza della \textit{time slice} usata dalla politica \textit{round robin};
+il suo prototipo è:
+\begin{prototype}{sched.h}
+  {int sched\_rr\_get\_interval(pid\_t pid, struct timespec *tp)} Legge in
+  \param{tp} la durata della \textit{time slice} per il processo \param{pid}.
+  
+  \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
+    nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+    \item[\errcode{ENOSYS}] la system call non è stata implementata.
+  \end{errlist}}
+\end{prototype}
+
+La funzione restituisce il valore dell'intervallo di tempo usato per la
+politica \textit{round robin} in una struttura \struct{timespec}, (la cui
+definizione si può trovare in fig.~\ref{fig:sys_timeval_struct}). In realtà
+dato che in Linux questo intervallo di tempo è prefissato e non modificabile,
+questa funzione ritorna sempre un valore di 150 millisecondi, e non importa
+specificare il PID di un processo reale.
+
+
+Come accennato ogni processo che usa lo scheduling real-time può rilasciare
+volontariamente la CPU; questo viene fatto attraverso la funzione
+\funcd{sched\_yield}, il cui prototipo è:
+\begin{prototype}{sched.h}
+  {int sched\_yield(void)} 
+  
+  Rilascia volontariamente l'esecuzione.
+  
+  \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
+    nel qual caso \var{errno} viene impostata opportunamente.}
+\end{prototype}
+
+La funzione fa sì che il processo rilasci la CPU, in modo da essere rimesso in
+coda alla lista dei processi da eseguire, e permettere l'esecuzione di un
+altro processo; se però il processo è l'unico ad essere presente sulla coda
+l'esecuzione non sarà interrotta. In genere usano questa funzione i processi
+in modalità \textit{fifo}, per permettere l'esecuzione degli altri processi
+con pari priorità quando la sezione più urgente è finita.
+
+Infine con il supporto dei sistemi multiprocessore sono state introdotte delle
+funzioni che permettono di controllare in maniera più dettagliata la scelta di
+quale processore utilizzare per eseguire un certo programma. Uno dei problemi
+che si pongono nei sistemi multiprocessore è infatti quello
+dell'\textsl{effetto ping-pong}.\index{\textsl{effetto ping-pong}} Può
+accadere cioè che lo scheduler, quando riavvia un processo precedentemente
+interrotto, scegliendo il primo processore disponibile lo faccia eseguire da
+un processore diverso rispetto a quello su cui era stato eseguito in
+precedenza. Se il processo passa da un processore all'altro in questo modo
+(cosa che avveniva abbastanza di frequente con i kernel della seria 2.4.x) si
+ha l'\textsl{effetto ping-pong}.
+
+Questo tipo di comportamento può generare dei seri problemi di prestazioni;
+infatti tutti i processori moderni utilizzano una memoria interna (la
+\textit{cache}) contenente i dati più usati, che permette di evitare di
+eseguire un accesso (molto più lento) alla memoria principale sulla scheda
+madre.  Chiaramente un processo sarà favorito se i suoi dati sono nella cache
+del processore, ma è ovvio che questo può essere vero solo per un processore
+alla volta, perché in presenza di più copie degli stessi dati su più
+processori, non si potrebbe determinare quale di questi ha la versione dei
+dati aggiornata rispetto alla memoria principale.
+
+Questo comporta che quando un processore inserisce un dato nella sua cache,
+tutti gli altri processori che hanno lo stesso dato devono invalidarlo, e
+questa operazione è molto costosa in termini di prestazioni. Il problema
+diventa serio quando si verifica l'\textsl{effetto ping-pong}, in tal caso
+infatti un processo \textsl{rimbalza} continuamente da un processore all'altro
+e si ha una continua invalidazione della cache, che non diventa mai
+disponibile. 
+
+Per ovviare a questo tipo di problemi è nato il concetto di \textsl{affinità
+  di processore} (o \index{\textit{CPU~affinity}}\textit{CPU affinity}); la
+possibilità cioè di far sì che un processo possa essere assegnato per
+l'esecuzione sempre allo stesso processore. Lo scheduler dei kernel della
+serie 2.4.x aveva una scarsa \textit{CPU affinity}, e l'effetto ping-pong era
+comune; con il nuovo scheduler dei kernel della 2.6.x questo problema è stato
+risolto ed esso cerca di mantenere il più possibile ciascun processo sullo
+stesso processore.
+
+In certi casi però resta l'esigenza di poter essere sicuri che un processo sia
+sempre eseguito dallo stesso processore,\footnote{quella che viene detta
+  \textit{hard CPU affinity}, in contrasto con quella fornita dallo scheduler,
+  detta \textit{soft CPU affinity}, che di norma indica solo una preferenza,
+  non un requisito assoluto.} e per poter risolvere questo tipo di
+problematiche nei nuovi kernel\footnote{le due system call per la gestione
+  della \textit{CPU affinity} sono state introdotte nel kernel 2.5.8, e le
+  funzioni di libreria nelle \textsl{glibc} 2.3.} è stata introdotta
+l'opportuna infrastruttura ed una nuova system call che permette di impostare
+su quali processori far eseguire un determinato processo attraverso una
+\textsl{maschera di affinità}. La corrispondente funzione di libreria è
+\funcd{sched\_setaffinity} ed il suo prototipo\footnote{di questa funzione (e
+  della corrispondente \func{sched\_setaffinity}) esistono versioni diverse
+  per gli argomenti successivi a \param{pid}: la prima (quella riportata nella
+  pagina di manuale) prevedeva due ulteriori argomenti di tipo
+  \texttt{unsigned int len} e \texttt{unsigned long *mask}, poi l'argomento
+  \texttt{len} è stato eliminato, successivamente si è introdotta la versione
+  riportata con però un secondo argomento di tipo \texttt{size\_t cpusetsize}
+  (anche questa citata nella pagina di manuale); la versione citata è quella
+  riportata nel manuale delle \textsl{glibc} e corripondente alla definizione
+  presente in \file{sched.h}.} è:
+\begin{prototype}{sched.h}
+  {int sched\_setaffinity (pid\_t pid, const cpu\_set\_t *cpuset)} 
+  Imposta la maschera di affinità del processo \param{pid}.
+  
+  \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
+    nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+    \item[\errcode{EINVAL}] il valore di \param{cpuset} contiene riferimenti a
+      processori non esistenti nel sistema.
+    \item[\errcode{EPERM}] il processo non ha i privilegi sufficienti per
+      eseguire l'operazione.
+  \end{errlist} 
+  ed inoltre anche \errval{EFAULT}.}
+\end{prototype}
+
+La funzione imposta, con l'uso del valore contenuto all'indirizzo
+\param{cpuset}, l'insieme dei processori sui quali deve essere eseguito il
+processo identificato tramite il valore passato in \param{pid}. Come in
+precedenza il valore nullo di \param{pid} indica il processo corrente.  Per
+poter utilizzare questa funzione sono richiesti i privilegi di amministratore
+(è necessaria la capacità \const{CAP\_SYS\_NICE}) altrimenti essa fallirà con
+un errore di \errcode{EPERM}. Una volta impostata una maschera di affinità,
+questa viene ereditata attraverso una \func{fork}, in questo modo diventa
+possibile legare automaticamente un gruppo di processi ad un singolo
+processore.
+
+Nell'uso comune, almeno con i kernel della serie 2.6.x, l'uso di questa
+funzione non è necessario, in quanto è lo scheduler stesso che provvede a
+mantenere al meglio l'affinità di processore. Esistono però esigenze
+particolari, ad esempio quando un processo (o un gruppo di processi) è
+utilizzato per un compito importante (ad esempio per applicazioni real-time o
+la cui risposta è critica) e si vuole la massima velocità, con questa
+interfaccia diventa possibile selezionare gruppi di processori utilizzabili in
+maniera esclusiva.  Lo stesso dicasi quando l'accesso a certe risorse (memoria
+o periferiche) può avere un costo diverso a seconda del processore (come
+avviene nelle architetture NUMA).
+
+Infine se un gruppo di processi accede alle stesse risorse condivise (ad
+esempio una applicazione con più thread) può avere senso usare lo stesso
+processore in modo da sfruttare meglio l'uso della sua cache; questo
+ovviamente riduce i benefici di un sistema multiprocessore nell'esecuzione
+contemporanea dei thread, ma in certi casi (quando i thread sono inerentemente
+serializzati nell'accesso ad una risorsa) possono esserci sufficienti vantaggi
+nell'evitare la perdita della cache da rendere conveniente l'uso dell'affinità
+di processore.
+
+Per facilitare l'uso dell'argomento \param{cpuset} le \acr{glibc} hanno
+introdotto un apposito dato di tipo, \ctyp{cpu\_set\_t},\footnote{questa è una
+  estensione specifica delle \acr{glibc}, da attivare definendo la macro
+  \macro{\_GNU\_SOURCE}, non esiste infatti una standardardizzazione per
+  questo tipo di interfaccia e POSIX al momento non prevede nulla al
+  riguardo.} che permette di identificare un insieme di processori. Il dato è
+una maschera binaria: in generale è un intero a 32 bit in cui ogni bit
+corrisponde ad un processore, ma dato che per architetture particolari il
+numero di bit di un intero può non essere sufficiente, è stata creata questa
+che è una interfaccia generica che permette di usare a basso livello un tipo
+di dato qualunque rendendosi indipendenti dal numero di bit e dalla loro
+disposizione.
+
+Questa interfaccia, oltre alla definizione del tipo di dato apposito, prevede
+anche una serie di macro di preprocessore per la manipolazione dello stesso,
+che consentono di svuotare un insieme, aggiungere o togliere un processore da
+esso o verificare se vi è già presente:
+\begin{functions}
+  \headdecl{sched.h}
+  \funcdecl{void \macro{CPU\_ZERO}(cpu\_set\_t *set)}
+  Inizializza l'insieme (vuoto).
+
+  \funcdecl{void \macro{CPU\_SET}(int cpu, cpu\_set\_t *set)}
+  Inserisce il processore \param{cpu} nell'insieme.
+
+  \funcdecl{void \macro{CPU\_CLR}(int cpu, cpu\_set\_t *set)}
+  Rimuove il processore \param{cpu} nell'insieme.
+  
+  \funcdecl{int \macro{CPU\_ISSET}(int cpu, cpu\_set\_t *set)}
+  Controlla se il processore \param{cpu} è nell'insieme.
+\end{functions}
+
+Oltre a queste macro, simili alle analoghe usate per gli insiemi di file
+descriptor (vedi sez.~\ref{sec:file_select}) è definita la costante
+\const{CPU\_SETSIZE} che indica il numero massimo di processori che possono
+far parte dell'insieme, e che costituisce un limite massimo al valore
+dell'argomento \param{cpu}.
+
+In generale la maschera di affinità è preimpostata in modo che un processo
+possa essere eseguito su qualunque processore, se può comunque leggere il
+valore per un processo specifico usando la funzione
+\funcd{sched\_getaffinity}, il suo prototipo è:
+\begin{prototype}{sched.h}
+  {int sched\_getaffinity (pid\_t pid, const cpu\_set\_t *cpuset)} 
+  Legge la maschera di affinità del processo \param{pid}.
+  
+  \bodydesc{La funzione ritorna 0 in caso di successo e -1 in caso di errore,
+    nel qual caso \var{errno} può assumere i valori:
+    \begin{errlist}
+    \item[\errcode{ESRCH}] il processo \param{pid} non esiste.
+    \item[\errcode{EFAULT}] il valore di \param{cpuset} non è un indirizzo
+      valido. 
+  \end{errlist} }
+\end{prototype}
+
+La funzione restituirà all'indirizzo specificato da \param{cpuset} il valore
+della maschera di affinità del processo, così da poterla riutilizzare per una
+successiva reimpostazione. In questo caso non sono necessari privilegi
+paricolari.  
+
+È chiaro che queste funzioni per la gestione dell'affinità hanno significato
+soltanto su un sistema multiprocessore, esse possono comunque essere
+utilizzate anche in un sistema con un processore singolo, nel qual caso però
+non avranno alcun risultato effettivo.
+
+
+\section{Problematiche di programmazione multitasking}
+\label{sec:proc_multi_prog}
+
+Benché i processi siano strutturati in modo da apparire il più possibile come
+indipendenti l'uno dall'altro, nella programmazione in un sistema multitasking
+occorre tenere conto di una serie di problematiche che normalmente non
+esistono quando si ha a che fare con un sistema in cui viene eseguito un solo
+programma alla volta.
+
+Pur essendo questo argomento di carattere generale, ci è parso opportuno
+introdurre sinteticamente queste problematiche, che ritroveremo a più riprese
+in capitoli successivi, in questa sezione conclusiva del capitolo in cui
+abbiamo affrontato la gestione dei processi.
+
+
+\subsection{Le operazioni atomiche}
+\label{sec:proc_atom_oper}
+
+La nozione di \textsl{operazione atomica} deriva dal significato greco della
+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.
+
+In un ambiente multitasking il concetto è essenziale, dato che un processo può
+essere interrotto in qualunque momento dal kernel che mette in esecuzione un
+altro processo o dalla ricezione di un segnale; occorre pertanto essere
+accorti nei confronti delle possibili 
+\textit{race condition}\index{\textit{race~condition}} (vedi
+sez.~\ref{sec:proc_race_cond}) derivanti da operazioni interrotte in una fase
+in cui non erano ancora state completate.
+
+Nel caso dell'interazione fra processi la situazione è molto più semplice, ed
+occorre preoccuparsi della atomicità delle operazioni solo quando si ha a che
+fare con meccanismi di intercomunicazione (che esamineremo in dettaglio in
+cap.~\ref{cha:IPC}) o nelle operazioni con i file (vedremo alcuni esempi in
+sez.~\ref{sec:file_atomic}). In questi casi in genere l'uso delle appropriate
+funzioni di libreria per compiere le operazioni necessarie è garanzia
+sufficiente di atomicità in quanto le system call con cui esse sono realizzate
+non possono essere interrotte (o subire interferenze pericolose) da altri
+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
+il solo accesso o l'assegnazione di una variabile possono non essere più
+operazioni atomiche (torneremo su questi aspetti in
+sez.~\ref{sec:sig_control}).
 
+In questo caso il sistema provvede un tipo di dato, il \type{sig\_atomic\_t},
+il cui accesso è assicurato essere atomico.  In pratica comunque si può
+assumere che, in ogni piattaforma su cui è implementato Linux, il tipo
+\ctyp{int}, gli altri interi di dimensione inferiore ed i puntatori sono
+atomici. Non è affatto detto che lo stesso valga per interi di dimensioni
+maggiori (in cui l'accesso può comportare più istruzioni in assembler) o per
+le strutture. In tutti questi casi è anche opportuno marcare come
+\direct{volatile} le variabili che possono essere interessate ad accesso
+condiviso, onde evitare problemi con le ottimizzazioni del codice.
 
-\subsection{Le funzioni \texttt{seteuid} e \texttt{setegid}}
-\label{sec:proc_seteuid}
 
 
-\subsection{Le \textit{race condition}}
+\subsection{Le \textit{race condition} ed i \textit{deadlock}}
 \label{sec:proc_race_cond}
 
-Si definisce una \textit{race condition} il caso in cui diversi processi
-stanno cercando di fare qualcosa con una risorsa comune ed il risultato finale
-viene a dipendere dall'ordine di esecuzione dei medesimi. Ovviamente dato che
-l'ordine di esecuzione di un processo, senza appositi meccanismi di
-sincronizzazione, non è assolutamente prevedibile, queste situazioni sono
-fonti di errori molto subdoli, che possono verificarsi solo in condizioni
-particolari e quindi difficilmente riproducibili.
+\index{\textit{race~condition}|(}
+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 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.
+
+Dato che in un sistema multitasking ogni processo può essere interrotto in
+qualunque momento per farne subentrare un altro in esecuzione, niente può
+assicurare un preciso ordine di esecuzione fra processi diversi o che una
+sezione di un programma possa essere eseguita senza interruzioni da parte di
+altri. Queste situazioni comportano pertanto errori estremamente subdoli e
+difficili da tracciare, in quanto nella maggior parte dei casi tutto
+funzionerà regolarmente, e solo occasionalmente si avranno degli errori. 
+
+Per questo occorre essere ben consapevoli di queste problematiche, e del fatto
+che l'unico modo per evitarle è quello di riconoscerle come tali e prendere
+gli adeguati provvedimenti per far sì che non si verifichino. Casi tipici di
+\textit{race condition} si hanno quando diversi processi accedono allo stesso
+file, o nell'accesso a meccanismi di intercomunicazione come la memoria
+condivisa. In questi casi, se non si dispone della possibilità di eseguire
+atomicamente le operazioni necessarie, occorre che quelle parti di codice in
+cui si compiono le operazioni sulle risorse condivise (le cosiddette
+\textsl{sezioni critiche}\index{sezioni~critiche}) del programma, siano
+opportunamente protette da meccanismi di sincronizzazione (torneremo su queste
+problematiche di questo tipo in cap.~\ref{cha:IPC}).
+
+\index{\textit{deadlock}|(} 
+Un caso particolare di \textit{race condition} sono poi i cosiddetti
+\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
+completo di un servizio, e non il fallimento di una singola operazione. Per
+definizione un \textit{deadlock} è una situazione in cui due o più processi
+non sono più in grado di proseguire perché ciascuno aspetta il risultato di
+una operazione che dovrebbe essere eseguita dall'altro.
+
+
+L'esempio tipico di una situazione che può condurre ad un
+\textit{deadlock} è quello in cui un flag di
+``\textsl{occupazione}'' viene rilasciato da un evento asincrono (come un
+segnale o un altro processo) fra il momento in cui lo si è controllato
+(trovandolo occupato) e la successiva operazione di attesa per lo sblocco. In
+questo caso, dato che l'evento di sblocco del flag è avvenuto senza che ce ne
+accorgessimo proprio fra il controllo e la messa in attesa, quest'ultima
+diventerà perpetua (da cui il nome di \textit{deadlock}).
+
+In tutti questi casi è di fondamentale importanza il concetto di atomicità
+visto in sez.~\ref{sec:proc_atom_oper}; questi problemi infatti possono essere
+risolti soltanto assicurandosi, quando essa sia richiesta, che sia possibile
+eseguire in maniera atomica le operazioni necessarie.
+\index{\textit{race~condition}|)}
+\index{\textit{deadlock}|)}
+
+
+\subsection{Le funzioni rientranti}
+\label{sec:proc_reentrant}
+
+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
+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 gestori dei segnali.
+
+Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
+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
+disposizione due macro di compilatore, \macro{\_REENTRANT} e
+\macro{\_THREAD\_SAFE}, la cui definizione attiva le versioni rientranti di
+varie funzioni di libreria, che sono identificate aggiungendo il suffisso
+\code{\_r} al nome della versione normale.
+
+
+
+%%% Local Variables: 
+%%% mode: latex
+%%% TeX-master: "gapil"
+%%% End: