% TODO la task_struct è cambiata per qualche dettaglio vedi anche
% http://www.ibm.com/developerworks/linux/library/l-linux-process-management/
+% TODO completare la parte su quando viene chiamato lo scheduler.
Come accennato in sez.~\ref{sec:intro_unix_struct} è lo \itindex{scheduler}
\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.}
-% TODO completare questa parte su quando viene chiamato lo scheduler.
-(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},\footnote{fino al kernel 2.4 il valore usuale di questa costante
- era 100, per tutte le architetture eccetto l'alpha, per la quale era 1000,
- nel 2.6 è stato portato a 1000 su tutte le architetture; occorre fare
- attenzione a non confondere questo valore con quello dei
- \itindex{clock~tick} \textit{clock tick} (vedi
+ di altre occasioni.} 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},\footnote{fino al kernel 2.4 il valore di \const{HZ} era 100 su
+ tutte le architetture tranne l'alpha, per cui era 1000, nel 2.6 è stato
+ portato a 1000 su tutte; dal 2.6.13 lo si può impostare in fase di
+ compilazione del kernel, con un default di 250 e valori possibili di 100,
+ 250, 1000 e dal 2.6.20 anche 300 (che è divisibile per le frequenze di
+ refresh della televisione); occorre fare attenzione a non confondere questo
+ valore con quello dei \itindex{clock~tick} \textit{clock tick} (vedi
sez.~\ref{sec:sys_unix_time}).} definita in \file{asm/param.h}, ed il cui
valore è espresso in Hertz.\footnote{a partire dal kernel 2.6.21 è stato
introdotto (a cura di Ingo Molnar) un meccanismo completamente diverso,
da parte del processore che può essere messo in stato di sospensione anche
per lunghi periodi di tempo.}
-
Ogni volta che viene eseguito, lo \itindex{scheduler} \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
\item i limiti sulle risorse (vedi sez.~\ref{sec:sys_resource_limit});
\item il valori di \textit{nice}, le priorità real-time e le affinità di
processore (vedi sez.~\ref{sec:proc_sched_stand},
- sez.~\ref{sec:proc_real_time} e sez.\ref{sec:proc_sched_multiprocess});
+ sez.~\ref{sec:proc_real_time} e sez.~\ref{sec:proc_sched_multiprocess});
\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:
per il figlio vengono cancellati.
\end{itemize*}
-
Una seconda funzione storica usata per la creazione di un nuovo processo è
\func{vfork}, che è esattamente identica a \func{fork} ed ha la stessa
semantica e gli stessi errori; la sola differenza è che non viene creata la
Dato che Linux supporta il \itindex{copy~on~write} \textit{copy on write} la
perdita di prestazioni è assolutamente trascurabile, e l'uso di questa
-funzione (che resta un caso speciale della system call \func{\_\_clone}) è
-deprecato; per questo eviteremo di trattarla ulteriormente.
+funzione, che resta un caso speciale della system call \func{clone} (che
+tratteremo in dettaglio in sez.~\ref{sec:process_clone}) è deprecato; per
+questo eviteremo di trattarla ulteriormente.
\subsection{La conclusione di un processo}
scrivere codice portabile.
-\section{La gestione della priorità di esecuzione}
+\section{La gestione della priorità dei processi}
\label{sec:proc_priority}
In questa sezione tratteremo più approfonditamente i meccanismi con il quale
lo \itindex{scheduler} \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.
+gestione. Tratteremo infine anche le altre priorità dei processi (come quelle
+per l'accesso a disco) divenute disponibili con i kernel più recenti.
+
\subsection{I meccanismi di \textit{scheduling}}
\label{sec:proc_sched}
\begin{table}[htb]
\footnotesize
\centering
- \begin{tabular}[c]{|p{2.8cm}|c|p{10cm}|}
+ \begin{tabular}[c]{|p{2.4cm}|c|p{9cm}|}
\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). \\
+ venga assegnata la CPU).\\
\textbf{Sleep} & \texttt{S} & Il processo è in attesa di un
risposta dal sistema, ma può essere
- interrotto da un segnale. \\
+ 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. \\
+ 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
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).
+o periferiche) può avere un costo diverso a seconda del processore, come
+avviene nelle architetture NUMA (\textit{Non-Uniform Memory Access}).
Infine se un gruppo di processi accede alle stesse risorse condivise (ad
esempio una applicazione con più \itindex{thread} \textit{thread}) può avere
\itindend{CPU~affinity}
+\subsection{Le priorità per le operazioni di I/O}
+\label{sec:io_priority}
+
+A lungo l'unica priorità usata per i processi è stata quella relativa
+all'assegnazione dell'uso del processore. Ma il processore non è l'unica
+risorsa che i processi devono contendersi, un'altra, altrettanto importante
+per le prestazioni, è quella dell'accesso a disco. Per questo motivo sono
+stati introdotti diversi \textit{I/O scheduler} in grado di distribuire in
+maniera opportuna questa risorsa ai vari processi. Fino al kernel 2.6.17 era
+possibile soltanto differenziare le politiche generali di gestione, scegliendo
+di usare un diverso \textit{I/O scheduler}; a partire da questa versione, con
+l'introduzione dello scheduler CFQ (\textit{Completely Fair Queuing}) è
+divenuto possibile, qualora si usi questo scheduler, impostare anche delle
+diverse priorità di accesso per i singoli processi.\footnote{al momento
+ (kernel 2.6.31), le priorità di I/O sono disponibili soltanto per questo
+ scheduler.}
+
+La scelta dello scheduler di I/O si può fare in maniera generica a livello di
+avvio del kernel assegnando il nome dello stesso al parametro
+\texttt{elevator}, mentre se ne può indicare uno per l'accesso al singolo
+disco scrivendo nel file \texttt{/sys/block/\textit{dev}/queue/scheduler}
+(dove \texttt{\textit{dev}} è il nome del dispositivo associato al disco); gli
+scheduler disponibili sono mostrati dal contenuto dello stesso file che
+riporta fra parentesi quadre quello attivo, il default in tutti i kernel
+recenti è proprio il \texttt{cfq},\footnote{nome con cui si indica appunto lo
+ scheduler \textit{Completely Fair Queuing}.} che supporta le priorità. Per i
+dettagli sulle caratteristiche specifiche degli altri scheduler, la cui
+discussione attiene a problematiche di ambito sistemistico, si consulti la
+documentazione nella directory \texttt{Documentation/block/} dei sorgenti del
+kernel.
+
+Una volta che si sia impostato lo scheduler CFQ ci sono due specifiche system
+call, specifiche di Linux, che consentono di leggere ed impostare le priorità
+di I/O.\footnote{se usate in corrispondenza ad uno scheduler diverso il loro
+ utilizzo non avrà alcun effetto.} Dato che non esiste una interfaccia
+diretta nelle \acr{glibc} per queste due funzioni occorrerà invocarle tramite
+la funzione \func{syscall} (come illustrato in
+sez.~\ref{sec:intro_syscall}). Le due funzioni sono \funcd{ioprio\_get} ed
+\funcd{ioprio\_set}; i rispettivi prototipi sono:
+\begin{functions}
+ \headdecl{linux/ioprio.h}
+ \funcdecl{int ioprio\_get(int which, int who)}
+ \funcdecl{int ioprio\_set(int which, int who, int ioprio)}
+
+ Rileva o imposta la priorità di I/O di un processo.
+
+ \bodydesc{Le funzioni ritornano rispettivamente un intero positivo
+ (indicante la priorità) o 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}] non esiste il processo indicato.
+ \item[\errcode{EINVAL}] i valori di \param{which} e \param{who} non sono
+ validi.
+ \item[\errcode{EPERM}] non si hanno i privilegi per eseguire
+ l'impostazione (solo per \func{ioprio\_set}).
+ \end{errlist} }
+\end{functions}
+
+Le funzioni leggono o impostano la priorità di I/O sulla base dell'indicazione
+dei due argomenti \param{which} e \param{who} che hanno lo stesso significato
+già visto per gli omonimi argomenti di \func{getpriority} e
+\func{setpriority}. Anche in questo caso si deve specificare il valore
+di \param{which} tramite le opportune costanti riportate in
+tab.~\ref{tab:ioprio_args} che consentono di indicare un singolo processo, i
+processi di un \textit{process group} (tratteremo questo argomento in
+sez.~\ref{sec:sess_proc_group}) o tutti o processi di un utente.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|c|c|l|}
+ \hline
+ \param{which} & \param{who} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IPRIO\_WHO\_PROCESS} & \type{pid\_t} & processo\\
+ \const{IPRIO\_WHO\_PRGR} & \type{pid\_t} & \itindex{process~group}
+ \textit{process group}\\
+ \const{IPRIO\_WHO\_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{ioprio\_get} e
+ \func{ioprio\_set} per le tre possibili scelte.}
+ \label{tab:ioprio_args}
+\end{table}
+
+In caso di successo \func{ioprio\_get} restituisce un intero positivo che
+esprime il valore della priorità di I/O, questo valore è una maschera binaria
+composta da due parti, una che esprime la \textsl{classe} di scheduling di I/O
+del processo, l'altra che esprime, quando la classe di scheduling lo prevede,
+la priorità del processo all'interno della classe stessa. Questo stesso
+formato viene utilizzato per indicare il valore della priorità da impostare
+con l'argomento \param{ioprio} di \func{ioprio\_set}.
+
+Per la gestione dei valori che esprimono le priorità di I/O sono state
+definite delle opportune macro di preprocessore, riportate in
+tab.~\ref{tab:IOsched_class_macro}. I valori delle priorità si ottengono o si
+impostano usando queste macro. Le prime due si usano con il valore restituito
+da \func{ioprio\_get} e per ottenere rispettivamente la classe di
+scheduling\footnote{restituita dalla macro con i valori di
+ tab.~\ref{tab:IOsched_class}.} e l'eventuale valore della priorità. La terza
+macro viene invece usata per creare un valore di priorità da usare come
+argomento di \func{ioprio\_set} per eseguire una impostazione.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|p{8cm}|}
+ \hline
+ \textbf{Macro} & \textbf{Significato}\\
+ \hline
+ \hline
+ \macro{IOPRIO\_PRIO\_CLASS}\texttt{(\textit{value})}
+ & dato il valore di una priorità come
+ restituito da \func{ioprio\_get} estrae il
+ valore della classe.\\
+ \macro{IOPRIO\_PRIO\_DATA}\texttt{(\textit{value})}
+ & dato il valore di una priorità come
+ restituito da \func{ioprio\_get} estrae il
+ valore della priorità.\\
+ \macro{IOPRIO\_PRIO\_VALUE}\texttt{(\textit{class},\textit{prio})}
+ & dato un valore di priorità ed una classe
+ ottiene il valore numerico da passare a
+ \func{ioprio\_set}.\\
+ \hline
+ \end{tabular}
+ \caption{Le macro per la gestione dei valori numerici .}
+ \label{tab:IOsched_class_macro}
+\end{table}
+
+Le classi di scheduling previste dallo scheduler CFQ sono tre, e ricalcano tre
+diverse modalità di distribuzione delle risorse analoghe a quelle già adottate
+anche nel funzionamento dello scheduler del processore. Ciascuna di esse è
+identificata tramite una opportuna costante, secondo quanto riportato in
+tab.~\ref{tab:IOsched_class}.
+
+La classe di priorità più bassa è \const{IOPRIO\_CLASS\_IDLE}; i processi in
+questa classe riescono ad accedere a disco soltanto quando nessun altro
+processo richiede l'accesso. Occorre pertanto usarla con molta attenzione,
+perché un processo in questa classe può venire completamente bloccato quando
+ci sono altri processi in una qualunque delle altre due classi che stanno
+accedendo al disco. Quando si usa questa classe non ha senso indicare un
+valore di priorità, dato che in questo caso non esiste nessuna gerarchia e la
+priorità è identica, la minima possibile, per tutti i processi.
+
+\begin{table}[htb]
+ \centering
+ \footnotesize
+ \begin{tabular}[c]{|l|l|}
+ \hline
+ \textbf{Classe} & \textbf{Significato} \\
+ \hline
+ \hline
+ \const{IOPRIO\_CLASS\_RT} & Scheduling di I/O \textit{real time}.\\
+ \const{IOPRIO\_CLASS\_BE} & Scheduling di I/O ordinario.\\
+ \const{IOPRIO\_CLASS\_IDLE}& Scheduling di I/O di priorità minima.\\
+ \hline
+ \end{tabular}
+ \caption{Costanti che identificano le classi di scheduling di I/O.}
+ \label{tab:IOsched_class}
+\end{table}
+
+La seconda classe di priorità di I/O è \const{IOPRIO\_CLASS\_BE} (il nome sta
+per \textit{best-effort}) che è quella usata ordinariamente da tutti
+processi. In questo caso esistono priorità diverse che consentono di
+assegnazione di una maggiore banda passante nell'accesso a disco ad un
+processo rispetto agli altri, con meccanismo simile a quello dei valori di
+\textit{nice} in cui si evita che un processo a priorità più alta possa
+bloccare indefinitamente quelli a priorità più bassa. In questo caso però le
+diverse priorità sono soltanto otto, indicate da un valore numerico fra 0 e 7
+e come per \textit{nice} anche in questo caso un valore più basso indica una
+priorità maggiore.
+
+
+Infine la classe di priorità di I/O \textit{real-time}
+\const{IOPRIO\_CLASS\_RT} ricalca le omonime priorità di processore: un
+processo in questa classe ha sempre la precedenza nell'accesso a disco
+rispetto a tutti i processi delle altre classi e di un processo nella stessa
+classe ma con priorità inferiore, ed è pertanto in grado di bloccare
+completamente tutti gli altri. Anche in questo caso ci sono 8 priorità diverse
+con un valore numerico fra 0 e 7, con una priorità più elevata per valori più
+bassi.
+
+In generale nel funzionamento ordinario la priorità di I/O di un processo
+viene impostata in maniera automatica nella classe \const{IOPRIO\_CLASS\_BE}
+con un valore ottenuto a partire dal corrispondente valore di \textit{nice}
+tramite la formula: $\mathtt{\mathit{prio}}=(\mathtt{\mathit{nice}}+20)/5$. Un
+utente ordinario può modificare con \func{ioprio\_set} soltanto le priorità
+dei processi che gli appartengono,\footnote{per la modifica delle priorità di
+ altri processi occorrono privilegi amministrativi, ed in particolare la
+ capacità \const{CAP\_SYS\_NICE} (vedi sez.~\ref{sec:proc_capabilities}).}
+cioè quelli il cui user-ID reale corrisponde all'user-ID reale o effettivo del
+chiamante. Data la possibilità di ottenere un blocco totale dello stesso, solo
+l'amministratore\footnote{o un processo con la capacità
+ \const{CAP\_SYS\_ADMIN} (vedi sez.~\ref{sec:proc_capabilities}).} può
+impostare un processo ad una priorità di I/O nella classe
+\const{IOPRIO\_CLASS\_RT} o \const{IOPRIO\_CLASS\_IDLE}.
+
+
+%TODO trattare le funzionalità per il NUMA
+% vedi man numa e le pagine di manuale relative
+% vedere anche dove metterle...
\section{Problematiche di programmazione multitasking}
\label{sec:proc_multi_prog}
% LocalWords: infop ALL WEXITED WSTOPPED WNOWAIT signo CLD EXITED KILLED page
% LocalWords: CONTINUED sources forking Spawned successfully executing exiting
% LocalWords: next cat for COMMAND pts bash defunct TRAPPED DUMPED Killable PR
-% LocalWords: SIGKILL static RLIMIT preemption PREEMPT VOLUNTARY IDLE
+% LocalWords: SIGKILL static RLIMIT preemption PREEMPT VOLUNTARY IDLE RTPRIO
+% LocalWords: Completely Fair compat Uniform CFQ Queuing elevator dev cfq RT
+% LocalWords: Documentation block syscall ioprio IPRIO CLASS class best effort
%%% Local Variables:
%%% mode: latex