Iniziato l'I/O sui file
[gapil.git] / prochand.tex
index 90e2e9f65806c5947bc4624d55cedf2324459031..97b9c5e7d6d35521cf0adb178b303a200e2ccc4a 100644 (file)
@@ -500,10 +500,9 @@ Quello che succede 
 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.
+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 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
@@ -537,11 +536,10 @@ sequenza impredicibile. Le modalit
 \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:
+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} se
-  settati).
+\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
@@ -553,12 +551,12 @@ padre e figlio avranno in comune:
 \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 la maschera dei segnali bloccati e le azioni installate.
 \item i segmenti di memoria condivisa agganciati al processo. 
-\item i limiti sulle risorse
+\item i limiti sulle risorse.
 \item le variabili di ambiente (vedi \secref{sec:proc_environ}).
 \end{itemize*}
-le differenze invece sono:
+le differenze fra padre e figlio dopo la \func{fork} invece sono:
 \begin{itemize*}
 \item il valore di ritorno di \func{fork}.
 \item il \textit{process id}. 
@@ -567,7 +565,7 @@ le differenze invece sono:
 \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.
+\item gli allarmi ed i segnali pendenti, che per il figlio vengono cancellati.
 \end{itemize*}
 
 
@@ -760,7 +758,7 @@ 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}}
+\subsection{Le funzioni \func{wait} e  \func{waitpid}}
 \label{sec:proc_wait}
 
 Abbiamo già accennato come uno degli usi possibili delle capacità multitasking
@@ -791,6 +789,7 @@ caso di errore; \var{errno} pu
   \item \macro{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
@@ -963,6 +962,7 @@ accessibili definendo la costante \macro{\_USE\_BSD}, sono:
   Prima versione, equivalente a \func{wait4(-1, \&status, opt, rusage)} è
   ormai deprecata in favore di \func{wait4}.
 \end{functions}
+\noindent 
 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:
@@ -992,7 +992,7 @@ struct rusage {
     \end{lstlisting}
   \end{minipage} 
   \normalsize 
-  \caption{La struttura \texttt{rusage} per la lettura delle informazioni dei 
+  \caption{La struttura \var{rusage} per la lettura delle informazioni dei 
     delle risorse usate da un processo.}
   \label{fig:proc_rusage_struct}
 \end{figure}
@@ -1004,7 +1004,7 @@ sono mantenuti sono: \var{ru\_utime}, \var{ru\_stime}, \var{ru\_minflt},
 \var{ru\_majflt}, e \var{ru\_nswap}.
 
 
-\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
@@ -1609,24 +1609,22 @@ Gli utenti normali possono settare l'\textit{effective id} solo al valore del
 \textit{real id} o del \textit{saved id}, l'amministratore può specificare
 qualunque valore. Queste funzioni sono usate per permettere a root di settare
 solo l'\textit{effective id}, dato che l'uso normale di \func{setuid} comporta
-il settagio di tutti gli identificatori.
+il settaggio di tutti gli identificatori.
  
 
-
 \subsection{Le funzioni \func{setfsuid} e \func{setfsgid}}
 \label{sec:proc_setfsuid}
 
 Queste funzioni sono usate per settare gli identificatori usati da Linux per
 il controllo dell'accesso ai file. Come già accennato in
-\secref{sec:proc_user_group} Linux definisce questo ulteriore gruppo di
-identificatori che di norma sono assolutamente equivalenti agli
-\textit{effective id} (ed in seguito faremo sempre riferimento a questi
-ultimi), dato che ogni cambiamento di questi ultimi viene immediatamente
-riportato sui \textit{filesystem id}.
+\secref{sec:proc_user_group} in Linux è definito questo ulteriore gruppo di
+identificatori, che di norma sono assolutamente equivalenti agli
+\textit{effective id}, dato che ogni cambiamento di questi ultimi viene
+immediatamente riportato sui \textit{filesystem id}.
 
 C'è un solo caso in cui si ha necessità di introdurre una differenza fra
-\textit{effective id} e i \textit{filesystem id}, che è per ovviare ad un
-problema di sicurezza che si presneta quando si deve implementare un server
+\textit{effective id} e \textit{filesystem id}, 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'\textit{effective id} o il \textit{real id} il server si
@@ -1636,8 +1634,8 @@ ha temporaneamente assunto l'identit
 quelli originari per quanto riguarda tutti gli altri controlli di accesso.
 
 Le due funzioni usate per cambiare questi identificatori sono \func{setfsuid}
-e \func{setfsgid}, sono specifiche di Linux e non devono essere usate se si
-intendono scrivere programmi portabili; i loro prototipi sono:
+e \func{setfsgid}, ovviamenete 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}
@@ -1653,49 +1651,117 @@ l'unico errore possibile 
 \end{functions}
 
 Queste funzioni hanno successo solo se il processo chiamante ha i privilegi di
-amministratore o se il valore specificato coincide con uno dei
-\textit{real}, \textit{effective} o \textit{saved id}.
-
-
+amministratore o, per gli altri utenti, se il valore specificato coincide con
+uno dei \textit{real}, \textit{effective} o \textit{saved id}.
 
 
 \section{Problematiche di programmazione multitasking}
 \label{sec:proc_multi_prog}
 
 Benché i processi siano strutturati in modo da apparire il più possibile come
-independenti l'uno dall'altro, nella programmazione in un sistema multiutente
+indipendenti l'uno dall'altro, nella programmazione in un sistema multiutente
 occorre tenere conto di tutta 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 non essendo tutto questo direttamente legato alla modalità specifica in
-cui il multitasking è implementato in un sistema unix-like, avendo affrontato
-la gestione dei processi in questo capitolo, tratteremo queste problematiche,
-e relative precauzioni ed accorgimenti, in questa sezione conclusiva.
-
-
-\subsection{Le funzioni rientranti}
-\label{sec:proc_reentrant}
-
-
-\subsection{I \textit{deadlock}}
-\label{sec:proc_deadlock}
+cui il multitasking è implementato in un sistema unix-like, né al solo
+concetto di multitasking (le stesse problematiche si presentano ad esempio
+nella gestione degli interrupt hardware), in questa sezione conclusiva del
+capitolo in cui abbiamo affrontato la gestione dei processi, introdurremo
+sinteticamente queste problematiche, che ritroveremo a più riprese in capitoli
+successivi, con una breve definizione della terminologia e delle loro
+caratteristiche di fondo.
 
 
 \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 una 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 è esseziale, 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} (vedi
+\secref{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
+\capref{cha:ipc}) o nella operazioni con i file (vedremo alcuni esempi in
+\secref{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.
 
-\subsection{Le \textit{race condition}}
+Nel caso dei segnali invece la situazione è molto più delicata, in quanto lo
+stesso processo può essere interrotto in qualunque momento, e le operazioni di
+un eventuale \textit{signal handler} saranno compiute nello stesso spazio di
+indirizzi. Per questo anche solo il solo accesso o l'assegnazione di una
+variabile possono non essere più operazioni atomiche (torneremo su questi
+aspetti in \secref{sec:sign_xxx}).
+
+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
+\type{int} (e 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 questi casi è anche opportuno marcare come \type{volatile} le
+variabili che possono essere interessate ad accesso condiviso, onde evitare
+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, 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.
+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}).
+
+Un caso particolare di \textit{race condition} sono poi i cosidetti
+\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, attesa che a questo punto diventerà
+perpetua (da cui il nome di \textit{deadlock}) in quanto l'evento di sblocco
+di questa è stato perso.
+
+
+\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.