+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
+\secref{sec:proc_hierarchy} questa scelta viene eseguita da una sezione
+apposita del kernel, lo \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 introduce anche la problematica dovuta alla scelta di
+quale sia la CPU più opportuna da utilizzare.\footnote{nei processori moderni
+ la presenza di ampie cache può rendere poco efficiente trasferire
+ l'esecuzione di un processo da una CPU ad un'altra, per cui occorrono
+ meccanismi per determinare quale è la migliore scelta fra le diverse CPU.}
+Tutto questo comunque appartiene alle sottigliezze dell'implementazione del
+kernel, e dal punto di vista dei programmi che girano in user space, anche
+quando si hanno più processori (e dei processi che sono eseguiti davvero in
+contemporanea), si può pensare alle politiche di scheduling come concernenti
+la risorsa \textsl{tempo di esecuzione}, la cui assegnazione sarà governata
+dagli stessi meccanismi di scelta di priorità, solo che nel caso di più
+processori sarà a disposizione di più di un processo alla volta.
+
+I processi non devono solo eseguire del codice, ad esempio molto spesso
+saranno impegnati in operazioni di I/O, possono venire bloccati da un
+comando dal terminale, 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
+\tabref{tab:proc_proc_states}; ma soltanto i processi che sono nello stato
+\textit{runnable} concorrono per l'esecuzione. Questo vuol di
+
+
+\begin{table}[htb]
+ \centering
+ \begin{tabular}[c]{|p{3cm}|c|p{8cm}|}
+ \hline
+ \textbf{Stato} & \texttt{STAT} & \textbf{Descrizione} \\
+ \hline
+ \hline
+ \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 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
+ \macro{SIGSTOP}, o è tracciato.\\
+ \textbf{Zombie} & \texttt{Z} & Il processo è terminato ma il suo stato di
+ terminazione non è ancora stato letto dal padre. \\
+ \hline
+ \end{tabular}
+ \caption{Elenco dei possibili stati di un processo in Linux, nella colonna
+ \texttt{STAT} si è riportata la corripondente lettera usata dal comando
+ \cmd{ps} nell'omonimo campo.}
+ \label{tab:proc_proc_states}
+\end{table}
+
+
+
+Si deve quindi tenere presente che l'utilizzo della CPU è soltanto una delle
+risorse che sono necessarie per l'esecuzione di un programma, e spesso non è
+neanche la più importante. Per questo motivo non è affatto detto che dare ad
+un programma la massima priorità di esecuzione abbia risultati significativi
+in termini di prestazioni.
+
+
+
+
+Una delle caratteristiche c
+
+la priorità assoluta viene invece ignorata per quelli che sono bloccati su una
+richiesta di I/O o in stato di \textit{sleep}
+
+
+
+Il meccanismo tradizionale di scheduling di Unix (che tratteremo in
+\secref{sec:proc_sched_stand}) è sempre stato basato su delle \textsl{priorità
+ dinamiche}, in modo da assicurare che tutti i processi, anche i meno
+importanti, possano ricevere un po' di tempo di CPU. In sostanza quando un
+processo ottiene la CPU la sua priorità viene diminuita. In questo modo alla
+fine, anche un processo con priorità iniziale molto bassa, finisce per avere
+una priorità sufficiente per essere eseguito.
+
+Lo standard POSIX.1b però ha introdotto il concetto di \textsl{priorità
+ assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione
+alla normale priorità dinamica), per tenere conto dei sistemi
+real-time,\footnote{per sistema real-time si intende un sistema in grado di
+ eseguire operazioni in 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, anche
+quando l'altro è in esecuzione (grazie al \textit{prehemptive scheduling}).
+Ovviamente questo avviene solo per i processi che sono pronti per essere
+eseguiti (cioè nello stato \textit{runnable}). La priorità assoluta viene in
+genere indicata con un numero intero, ed un valore più alto comporta una
+priorità maggiore. Su questa politica di scheduling torneremo in
+\secref{sec:proc_real_time}.
+
+In generale quello che succede in tutti gli Unix moderni è che ai processi
+normali viene sempre data una priorità assoluta pari a zero, e la decisione di
+assegnazione della CPU è fatta solo in base ad una priorità dinamica che è
+calcolata indipendentemente. È tuttavia possibile assegnare anche una priorità
+assoluta nel qual caso un processo avrà la precedenza su tutti gli altri di
+priorità inferiore che saranno eseguiti solo quando quest'ultimo non avrà
+bisogno della CPU.
+
+
+\subsection{Il meccanismo di \textit{scheduling} standard}
+\label{sec:proc_sched_stand}
+
+A meno che non si abbiano 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.
+
+
+
+
+\subsection{Il meccanismo di \textit{scheduling real-time}}
+\label{sec:proc_real_time}
+
+Per settare le
+
+
+\footnote{a meno che non si siano installate le patch di RTLinux o RTAI, con i
+ quali è possibile ottenere un sistema effettivamente hard real-time.}
+
+in realtà non si tratta di un vero hard real-time, in quanto
+ la presenza di eventuali interrupt o di page fault può sempre interrompere
+ l'esecuzione di un processo, a meno di non installare le estensioni di
+ RTLinux o RTAI, il normale kernel non è real-time.
+
+
+
+
+
+\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} (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 nelle 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.
+
+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
+\secref{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
+\type{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
+\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 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}) 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}, 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 (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 \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.
+
+
+\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 manipolatori 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: