Correzioni
[gapil.git] / prochand.tex
index 685827ad30f0149e6661ab413fafe5c703155d8c..e50895c68b5c0cb2bf6419854b9481370ca82c69 100644 (file)
@@ -1,26 +1,28 @@
 \chapter{La gestione dei processi}
 \label{cha:process_handling}
 
-Come accennato nell'introduzione in un sistema unix ogni attività del sistema
+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.
 
-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. Infine nella sezione finale affronteremo alcune
-problematiche generiche della programmazione in ambiente multitasking.
+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 distruzione dei processi, della gestione dei loro attributi e privilegi,
+e di tutte le funzioni a questo connesse. Infine nella sezione finale
+affronteremo 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 un sistema unix-like. 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 una introduzione generale ai concetti che stanno alla base
+della gestione dei processi in un sistema unix-like. Introdurremo in questa
+sezione l'architettura della gestione dei processi e le sue principali
+caratteristiche, dando una panoramica sull'uso delle principali funzioni di
+gestione.
 
 
 \subsection{La gerarchia dei processi}
@@ -28,13 +30,13 @@ per la gestione dei processi.
 
 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}.
 
-Una seconda caratteristica di un sistema unix è che la generazione di un
+Una seconda caratteristica di un sistema Unix è che la generazione di un
 processo è una 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
@@ -190,8 +192,8 @@ ottenuti da programma usando le funzioni:
 \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
+\funcdecl{pid\_t getpid(void)} Restituisce il pid del processo corrente.
+\funcdecl{pid\_t getppid(void)} Restituisce il pid del padre del processo
     corrente.
 
 \bodydesc{Entrambe le funzioni non riportano condizioni di errore.}
@@ -234,16 +236,18 @@ prototipo della funzione 
   \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{Restituisce zero al padre e il \acr{pid} al figlio in caso di
+    successo, ritorna -1 al padre (senza creare il figlio) in caso di errore;
+    \var{errno} può assumere i valori:
   \begin{errlist}
   \item[\macro{EAGAIN}] non ci sono risorse sufficienti per creare un'altro
     processo (per allocare la tabella delle pagine e le strutture del task) o
     si è esaurito il numero di processi disponibili.
   \item[\macro{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
@@ -782,7 +786,6 @@ prototipo 
 Sospende il processo corrente finché un figlio non è uscito, o finché un
 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:
@@ -818,16 +821,17 @@ questa funzione; il suo prototipo 
 \headdecl{sys/types.h}
 \headdecl{sys/wait.h}
 \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 \macro{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
     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}
+  \end{errlist}}
 \end{functions}
 
 Le differenze principali fra le due funzioni sono che \func{wait} si blocca
@@ -960,7 +964,7 @@ accessibili definendo la costante \macro{\_USE\_BSD}, sono:
   \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
+  È 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:sys_xxx})
   \funcdecl{pid\_t wait3(int *status, int options, struct rusage *rusage)}
@@ -1296,14 +1300,17 @@ identificatori, chiamati rispettivamente \textit{real} ed \textit{effective}.
     il programma\\ 
     \acr{gid}   & \textit{real group id} & indica il gruppo dell'utente 
     che ha lanciato il programma \\ 
+    \hline
     \acr{euid}  & \textit{effective user id} & indica l'utente usato
     dal programma nel controllo di accesso \\ 
     \acr{egid}  & \textit{effective group id} & indica il gruppo 
     usato dal programma  nel controllo di accesso \\ 
     --          & \textit{supplementary group id} & indica i gruppi cui
     l'utente appartiene  \\ 
+    \hline
     --          & \textit{saved user id} &  copia dell'\acr{euid} iniziale\\ 
     --          & \textit{saved group id} &  copia dell'\acr{egid} iniziale \\ 
+    \hline
     \acr{fsuid} & \textit{filesystem user id} & indica l'utente effettivo per
     il filesystem \\ 
     \acr{fsgid} & \textit{filesystem group id} & indica il gruppo effettivo
@@ -1347,16 +1354,16 @@ prototipi sono i seguenti:
 \begin{functions}
   \headdecl{unistd.h}
   \headdecl{sys/types.h}  
-  \funcdecl{uid\_t getuid(void)} restituisce il \textit{real user ID} del
+  \funcdecl{uid\_t getuid(void)} Restituisce il \textit{real user ID} del
   processo corrente.
 
-  \funcdecl{uid\_t geteuid(void)} restituisce l'\textit{effective user ID} del
+  \funcdecl{uid\_t geteuid(void)} Restituisce l'\textit{effective user ID} del
   processo corrente.
 
-  \funcdecl{gid\_t getgid(void)} restituisce il \textit{real group ID} del
+  \funcdecl{gid\_t getgid(void)} Restituisce il \textit{real group ID} del
   processo corrente.
 
-  \funcdecl{gid\_t getegid(void)} restituisce l'\textit{effective group ID} del
+  \funcdecl{gid\_t getegid(void)} Restituisce l'\textit{effective group ID} del
   processo corrente.
   
   \bodydesc{Queste funzioni non riportano condizioni di errore.}
@@ -1414,10 +1421,10 @@ seguono la semantica POSIX che prevede l'esistenza di \textit{saved user id} e
 \headdecl{unistd.h}
 \headdecl{sys/types.h}
 
-\funcdecl{int setuid(uid\_t uid)} setta l'\textit{user ID} del processo
+\funcdecl{int setuid(uid\_t uid)} Setta l'\textit{user ID} del processo
 corrente.
 
-\funcdecl{int setgid(gid\_t gid)} setta il \textit{group ID} del processo
+\funcdecl{int setgid(gid\_t gid)} Setta il \textit{group ID} del processo
 corrente.
 
 \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
@@ -1513,11 +1520,11 @@ prototipi sono:
 \headdecl{unistd.h}
 \headdecl{sys/types.h}
 
-\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} setta il \textit{real user
+\funcdecl{int setreuid(uid\_t ruid, uid\_t euid)} Setta il \textit{real user
   ID} e l'\textit{effective user ID} del processo corrente ai valori
 specificati da \var{ruid} e \var{euid}.
   
-\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} setta il \textit{real group
+\funcdecl{int setregid(gid\_t rgid, gid\_t egid)} Setta il \textit{real group
   ID} e l'\textit{effective group ID} del processo corrente ai valori
 specificati da \var{rgid} e \var{egid}.
 
@@ -1567,12 +1574,12 @@ e permettono un completo controllo su tutti gli identificatori (\textit{real},
 \headdecl{unistd.h}
 \headdecl{sys/types.h}
 
-\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} setta il
+\funcdecl{int setresuid(uid\_t ruid, uid\_t euid, uid\_t suid)} Setta il
 \textit{real user ID}, l'\textit{effective user ID} e il \textit{saved user
   ID} del processo corrente ai valori specificati rispettivamente da
 \var{ruid}, \var{euid} e \var{suid}.
   
-\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} setta il
+\funcdecl{int setresgid(gid\_t rgid, gid\_t egid, gid\_t sgid)} Setta il
 \textit{real group ID}, l'\textit{effective group ID} e il \textit{saved group
   ID} del processo corrente ai valori specificati rispettivamente da
 \var{rgid}, \var{egid} e \var{sgid}.
@@ -1599,10 +1606,10 @@ supportate dalla maggior parte degli unix) e usate per cambiare gli
 \headdecl{unistd.h}
 \headdecl{sys/types.h}
 
-\funcdecl{int seteuid(uid\_t uid)} setta l'\textit{effective user ID} del
+\funcdecl{int seteuid(uid\_t uid)} Setta l'\textit{effective user ID} del
 processo corrente a \var{uid}.
 
-\funcdecl{int setegid(gid\_t gid)} setta l'\textit{effective group ID} del
+\funcdecl{int setegid(gid\_t gid)} Setta l'\textit{effective group ID} del
 processo corrente a \var{gid}.
 
 \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
@@ -1643,10 +1650,10 @@ usate se si intendono scrivere programmi portabili; i loro prototipi sono:
 \begin{functions}
 \headdecl{sys/fsuid.h}
 
-\funcdecl{int setfsuid(uid\_t fsuid)} setta il \textit{filesystem user ID} del
+\funcdecl{int setfsuid(uid\_t fsuid)} Setta il \textit{filesystem user ID} del
 processo corrente a \var{fsuid}.
 
-\funcdecl{int setfsgid(gid\_t fsgid)} setta l'\textit{filesystem group ID} del
+\funcdecl{int setfsgid(gid\_t fsgid)} Setta l'\textit{filesystem group ID} del
 processo corrente a \var{fsgid}.
 
 \bodydesc{Le funzioni restituiscono 0 in caso di successo e -1 in caso
@@ -1724,47 +1731,85 @@ problemi con le ottimizzazioni del codice.
 \subsection{Le \textit{race condition} e 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 rispetto agli altri, 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.
-
-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 le risorse
-condivise siano opportunamente protette da meccanismi di sincronizzazione
-(torneremo su queste problematiche di questo tipo in \secref{sec:ipc_semaph}).
+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 è quella di una 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 consapovoli di queste problematiche, e del fatto
+che l'unico modo per evitarle è quello di riconoscerle come tali e prendere
+gli adeguati provvedimenti per far si 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 critiche sulle risorse condivise, le cosiddette
+\textsl{sezioni critiche} del programma, siano opportunamente protette da
+meccanismi di sincronizzazione (torneremo su queste problematiche di questo
+tipo in \secref{sec:ipc_semaph}).
 
 Un caso particolare di \textit{race condition} sono poi i cosiddetti
-\textit{deadlock}; l'esempio tipico è quello di un flag di ``occupazione'' che
-viene rilasciato da un evento asincrono fra il controllo (in cui viene trovato
-occupato) e la successiva messa in attesa, che a questo punto diventerà
-perpetua (da cui il nome di \textit{deadlock}) in quanto l'evento di sblocco
-del flag è stato perso fra il controllo e la messa in attesa.
+\textit{deadlock}, particolarmente gravi in quanto comportano spesso il blocco
+completo di un servizio, e non il fallimento di una singola operazione.
+L'esempio tipico di una situazione che può condurre ad un \textit{deadlock} è
+quello in cui un flag di ``occupazione'' viene rilasciato da un evento
+asincrono (come un segnale o un altro processo) fra il momento in cui lo si è
+controllato (trovadolo 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 \secref{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, proteggendo con gli
+adeguati meccanismi le \textsl{sezioni critiche} del programma.
 
 
 \subsection{Le funzioni rientranti}
 \label{sec:proc_reentrant}
 
-Si dice rientrante una funzione che può essere interrotta in qualunque momento
-ed essere chiamata da capo (da questo il nome) da un altro filone di
-esecuzione (thread e manipolatori di segnali sono i casi in cui occorre
-prestare attenzione a questa problematica) senza che questo comporti nessun
-problema.
-
-In genere una funzione non è rientrante se opera direttamente su memoria che
-non è nello stack. Ad esempio una funzione non è rientrante se usa una
-variabile globale o statica od un oggetto allocato dinamicamente che trova da
-sola: due chiamate alla stessa funzione interferiranno.  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. 
-
-Le glibc mettono a disposizione due macro di compilatore \macro{\_REENTRANT} e
-\macro{\_THREAD\_SAFE} per assicurare che siano usate delle versioni rientranti
-delle funzioni di libreria.
+Si dice \textsl{rientrante} una funzione che può essere interrotta in
+qualunque punto della sua esecuzione ed essere chiamata una seconda volta da
+un altro thread di esecuzione senza che questo comporti nessun problema nella
+esecuzione della stessa. La problematica è comune nella programmazione
+multi-thread, ma si hanno gli stessi problemi quando si vogliono chiamare
+delle funzioni all'interno dei manipolatori dei segnali.
+
+Fintanto che una funzione opera soltanto con le variabili locali è rientrante;
+queste infatti vengono tutte le volte allocate nello stack, e un'altra
+invocazione non fa altro che allocarne un'altra copia. Una funzione può non
+essere rientrante quando opera su memoria che non è nello stack.  Ad esempio
+una funzione non è mai rientrante se usa una variabile globale o statica.
+
+Nel caso invece la funzione operi su un oggetto allocato dinamicamente la cosa
+viene a dipendere da come avvengono le operazioni; se l'oggetto è creato ogni
+volta e ritornato indietro la funzione può essere rientrante, se invece esso
+viene individuato dalla funzione stessa due chiamate alla stessa funzione
+potranno interferire quando entrambe faranno riferimento allo stesso oggetto.
+Allo stesso modo una funzione può non essere rientrante se usa e modifica un
+oggetto che le viene fornito dal chiamante: due chiamate possono interferire
+se viene passato lo stesso oggetto; in tutti questi casi occorre molta cura da
+parte del programmatore.
+
+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
+\func{\_r} al nome della versione normale.
+
+
+