Aggiuno un altro esempio
[gapil.git] / prochand.tex
index 582831aa8eb6dc908ab4b8a56c526fcbb37594aa..73f2e7fb7e154388c55ce952497a41d5ab27e972 100644 (file)
@@ -113,13 +113,12 @@ organizzati in un albero di directory (si veda
 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 nella
 tabella dei processi costituita da una struttura \type{task\_struct}, 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
+uno schema semplificato, che riporta la struttura delle principali informazioni
 contenute nella \type{task\_struct} (che in seguito incontreremo a più
 riprese), è mostrato in \nfig.
 
@@ -134,13 +133,14 @@ riprese), 
 
 Come accennato in \secref{sec:intro_unix_struct} è lo \textit{scheduler} che
 decide quale processo mettere in esecuzione; esso viene eseguito ad ogni
-system call ed ad ogni interrupt, (ma può essere anche attivato
+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 \macro{HZ}, definita in \file{asm/param.h} Il
-valore usuale è 100\footnote{è così per tutte le archietetture eccetto
-  l'alpha, per la quale è 1000} (è espresso in Hertz), si ha cioè un interrupt
-dal timer ogni centesimo di secondo.
+specificata dalla costante \macro{HZ}, definita in \file{asm/param.h}. Il
+valore usuale è 100\footnote{è così per tutte le architetture eccetto l'alpha,
+  per la quale è 1000} ed è espresso in Hertz. Si ha cioè un interrupt dal
+timer ogni centesimo di secondo.
 
 Ogni volta che viene eseguito, lo \textit{scheduler} effettua il calcolo delle
 priorità dei vari processi attivi (torneremo su questo in
@@ -895,18 +895,18 @@ specchietto riportato in \ntab:
 \begin{table}[!htb]
   \centering
   \footnotesize
-  \begin{tabular}[c]{|c|p{10cm}|}
+  \begin{tabular}[c]{|c|c|p{8cm}|}
     \hline
-    \textbf{Valore} & \textbf{Significato}\\
+    \textbf{Valore} & \textbf{Macro} &\textbf{Significato}\\
     \hline
     \hline
-    $<-1$& attende per un figlio il cui \textit{process group} è uguale al
+    $<-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
+    $-1$ & \macro{WAIT\_ANY} & attende per un figlio qualsiasi, usata in
+    questa maniera è equivalente a \func{wait}.\\ 
+    $0$  & \macro{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 \var{pid}.\\
     \hline
   \end{tabular}
@@ -1348,7 +1348,7 @@ rispettivamente \textit{real} ed \textit{effective}.
     \hline
   \end{tabular}
   \caption{Identificatori di utente e gruppo associati a ciascun processo con
-    indicazione dei suffissi usate dalle varie funzioni di manipolazione.}
+    indicazione dei suffissi usati dalle varie funzioni di manipolazione.}
   \label{tab:proc_uid_gid}
 \end{table}
 
@@ -1424,11 +1424,11 @@ processo, come copie dell'\textit{effective user id} e dell'\textit{effective
 fossero utente e gruppo effettivi all'inizio dell'esecuzione di un nuovo
 programma.
 
-Il \textit{filesystem user id} e il \textit{filesystem group id} sono una
-estensione introdotta in Linux per rendere più sicuro l'uso di NFS (torneremo
-sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una replica dei
-corrispondenti \textit{effective id}, ai quali si sostituiscono per tutte le
-operazioni di verifica dei permessi relativi ai file (trattate in
+Il \textit{filesystem user id} e il \textit{filesystem group id} sono
+un'estensione introdotta in Linux per rendere più sicuro l'uso di NFS
+(torneremo sull'argomento in \secref{sec:proc_setfsuid}). Essi sono una
+replica dei corrispondenti \textit{effective id}, ai quali si sostituiscono
+per tutte le operazioni di verifica dei permessi relativi ai file (trattate in
 \secref{sec:file_perm_overview}).  Ogni cambiamento effettuato sugli
 \textit{effective id} viene automaticamente riportato su di essi, per cui in
 condizioni normali se ne può tranquillamente ignorare l'esistenza, in quanto
@@ -1588,9 +1588,10 @@ Lo stesso problema di propagazione dei privilegi ad eventuali processi figli
 si porrebbe per i \textit{saved id}: queste funzioni derivano da
 un'implementazione che non ne prevede la presenza, e quindi non è possibile
 usarle per correggere la situazione come nel caso precedente. Per questo
-motivo in Linux tutte le volte che vengono usate per modificare uno degli
-identificatori ad un valore diverso dal \textit{real id} precedente, il
-\textit{saved id} viene sempre settato al valore dell'\textit{effective id}.
+motivo in Linux tutte le volte che tali funzioni vengono usate per modificare
+uno degli identificatori ad un valore diverso dal \textit{real id} precedente,
+il \textit{saved id} viene sempre settato al valore dell'\textit{effective
+  id}.
 
 
 
@@ -1821,11 +1822,9 @@ quando si definisce \macro{\_POSIX\_SOURCE} o si compila con il flag
 \label{sec:proc_priority}
 
 In questa sezione tratteremo più approfonditamente i meccanismi con il quale
-lo \textit{scheduler}\footnote{che è la parte del kernel che si occupa di
-  stabilire quale processo dovrà essere posto in esecuzione.} assegna la CPU
-ai vari processi attivi. In particolare prenderemo in esame i vari meccanismi
-con cui viene gestita l'assegnazione del tempo di CPU, ed illustreremo le
-varie funzioni di gestione.
+lo \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}}
@@ -1836,6 +1835,16 @@ il tempo di CPU per l'esecuzione dei processi 
 ed oggetto di numerose ricerche; in ogni caso essa dipende in maniera
 essenziale anche dal tipo di utilizzo che deve essere fatto del sistema.
 
+
+La 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
@@ -1850,12 +1859,63 @@ la risorsa \textsl{tempo di esecuzione}, la cui assegnazione sar
 dagli stessi meccanismi di scelta di priorità, solo che nel caso di più
 processori sarà a disposizione di più di un processo alla volta.
 
-Si tenga presente inoltre che l'utilizzo della CPU è soltanto una delle
-risorse (insieme alla memoria e all'accesso alle periferiche) che sono
-necessarie per l'esecuzione di un programma, e spesso non è neanche la più
-importante. Per questo non è affatto detto che dare ad un programma la massima
-priorità di esecuzione abbia risultati significativi in termini di
-prestazioni.
+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à
@@ -1869,29 +1929,23 @@ Lo standard POSIX.1b per
   assoluta}, (chiamata anche \textsl{priorità statica}, in contrapposizione
 alla normale priorità dinamica), per tenere conto dei sistemi
 real-time,\footnote{per sistema real-time si intende un sistema in grado di
-  eseguire operazioni in tempo reale; in genere si tende a distinguere fra
-  l'\textit{hard real-time} in cui è necessario che i tempi di esecuzione di
-  un programma siano determinabili con certezza assoluta, come nel caso di
-  meccanismi di controllo di macchine, dove uno sforamento dei tempi avrebbe
-  conseguenze disastrose, e \textit{soft-real-time} in cui un occasionale
-  sforamento è ritenuto accettabile.} in cui è vitale che i processi che
-devono essere eseguiti in un determinato momento non debbano aspettare la
-conclusione di altri che non hanno questa necessità.
+  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},\footnote{lo stato di un processo
-  è riportato nel campo \texttt{STAT} dell'output del comando \cmd{ps},
-  abbiamo già visto che lo stato di \textit{zombie} è indicato con \texttt{Z},
-  gli stati \textit{runnable}, \textit{sleep} e di I/O (\textit{uninteruttible
-    sleep}) sono invece indicati con \texttt{R}, \texttt{S} e \texttt{D}.})
-la priorità assoluta viene invece ignorata per quelli che sono bloccati su una
-richiesta di I/O o in stato di \textit{sleep}.  La priorità assoluta viene in
+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}.  
+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
@@ -1905,15 +1959,18 @@ bisogno della CPU.
 \subsection{Il meccanismo di \textit{scheduling} standard}
 \label{sec:proc_sched_stand}
 
-A meno che non si abbiano specifiche esigenze, l'unico meccanismo di
-scheduling con il quale si avrà a che fare è quello tradizionale che prevede
-solo priorità dinamiche, ed è di questo che di norma ci si dovrà preoccupare
+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é viene varia nel corso dell'esecuzione di un processo.
+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.
 
 
 
@@ -1982,7 +2039,8 @@ 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:sign_xxx}).
+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ò
@@ -1995,6 +2053,7 @@ le strutture. In tutti questi casi 
 condiviso, onde evitare problemi con le ottimizzazioni del codice.
 
 
+
 \subsection{Le \textit{race condition} e i \textit{deadlock}}
 \label{sec:proc_race_cond}
 
@@ -2016,7 +2075,7 @@ funzioner
 
 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 si che non si verifichino. Casi tipici di
+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
@@ -2062,12 +2121,12 @@ 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.
+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