\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}
terminato; si potrebbe avere cioè quello che si chiama un processo
\textsl{orfano}.
-% TODO verificare il reparenting
-
Questa complicazione viene superata facendo in modo che il processo orfano
venga \textsl{adottato} da \cmd{init}. Come già accennato quando un processo
termina, il kernel controlla se è il padre di altri processi in esecuzione: in
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.
-% TODO: rivedere alla luce degli aggiornamenti del 2.6 (man sched_setscheduler)
\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
2.6.25, sostanzialmente identico
all'\textbf{Uninterrutible Sleep} con la
sola differenza che il processo può
- terminato (con \const{SIGKILL}).\\
+ terminato con \const{SIGKILL} (usato per
+ lo più per NFS).\\
\hline
\end{tabular}
\caption{Elenco dei possibili stati di un processo in Linux, nella colonna
\label{tab:proc_proc_states}
\end{table}
-% TODO nel 2.6.25 è stato aggiunto TASK_KILLABLE, da capire dova va messo.
-
Si deve quindi tenere presente che l'utilizzo della CPU è soltanto una delle
risorse che sono necessarie per l'esecuzione di un programma, e a seconda
dello scopo del programma non è detto neanche che sia la più importante (molti
da essere rimesso in coda alla lista dei processi con la stessa priorità per
permettere ad un altro di essere eseguito; se però il processo è l'unico ad
essere presente sulla coda l'esecuzione non sarà interrotta. In genere usano
-questa funzione i processi in modalità \textit{fifo}, per permettere
+questa funzione i processi con politica \const{SCHED\_FIFO}, per permettere
l'esecuzione degli altri processi con pari priorità quando la sezione più
urgente è finita.
-% TODO: con il 2.6.23 il comportamento è stato leggermente modificato ed è
-% stato introdotto /proc/sys/kernel/sched_compat_yield da mettere a 1 per aver
-% la compatibilità con il precedente.
+La funzione può essere utilizzata anche con processi che usano lo scheduling
+ordinario, ma in questo caso il comportamento non è ben definito, e dipende
+dall'implementazione. Fino al kernel 2.6.23 questo comportava che i processi
+venissero messi in fondo alla coda di quelli attivi, con la possibilità di
+essere rimessi in esecuzione entro breve tempo, con l'introduzione del
+\textit{Completely Fair Scheduler} questo comportamento è cambiato ed un
+processo che chiama la funzione viene inserito nella lista dei processi
+inattivo, con un tempo molto maggiore.\footnote{è comunque possibile
+ ripristinare un comportamento analogo al precedente scrivendo il valore 1
+ nel file \texttt{/proc/sys/kernel/sched\_compat\_yield}.}
+
+
\subsection{Il controllo dello \textit{scheduler} per i sistemi
multiprocessore}
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 librerie del C per queste due funzioni occorrerà invocarle
+tramite la funzione \func{syscall} (come illustrato in
+sez.~\ref{sec:intro_syscall}). La prima delle due è \funcd{ioprio\_get}, che
+consente di leggere la priorità; il suo prototipo è:
+\begin{prototype}{linux/ioprio.h}
+ {int ioprio\_get(int which, int who)}
+ Legge la priorità di I/O.
+
+ \bodydesc{La funzione ritorna un valore positivo 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.
+ \end{errlist} }
+\end{prototype}
+
+La funzione legge 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 analoghi argomenti di \func{getpriority} e \func{setpriority};
+in questo caso vengono però per \param{which} sono state definite delle
+costanti apposite, illustrate in tab.~\ref{tab:ioprio_args}. A seconda dei
+valori è così possibile leggere delle priorità per il singolo processo, per i
+processi di un \textit{process group} (tratteremo questo argomento in
+sez.~\ref{sec:sess_proc_group}) o per 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}
+
+Gli stessi valori possono essere utilizzati anche quando si vuole eseguire
+l'impostazione di una priorità di I/O; in tal caso si deve usare la funzione
+\funcd{ioprio\_set}, il cui prototipo è:
+\begin{prototype}{linux/ioprio.h}
+ {int ioprio\_set(int which, int who, int ioprio)}
+
+ Imposta la priorità di I/O.
+
+ \bodydesc{La funzione ritorna 0 in caso di successo e $-1$ in caso di
+ errore, nel qual caso \var{errno} può assumere i valori:
+ \begin{errlist}
+ \item[\errcode{EPERM}] non si hanno i privilegi per eseguire
+ l'impostazione.
+ \end{errlist}
+ oltre a \errcode{EINVAL} e \errcode{ESRCH} con lo stesso significato di
+ \func{ioprio\_get}. }
+\end{prototype}
+
+
+La funzione in caso di successo restituisce un intero positivo che esprime il
+valore della priorità di I/O, questo è composto di due parti, una che esprime
+la cosiddetta \textsl{classe} di scheduling, l'altro che esprime la priorità
+all'interno della classe stessa. Le classi previste dallo scheduler CFQ sono
+tre, identificate da altrettanti costanti, riportate in
+tab.~\ref{tab:IOsched_class}.
+
+\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 tre classi ricalcano i concetti presenti anche nello scheduler della CPU;
+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 di priorità più alta che stanno accedendo al
+disco; in questa classe non esistono valori di priorità, tutti i processi
+hanno la stessa priorità, che è la minima possibile.
+
+La classe per le priorità ordinarie è \const{IOPRIO\_CLASS\_BE} (il nome sta
+per \textit{best-effort}) che è quella usata di default per tutti processi; in
+questo caso esistono delle priorità all'interno della classe che corrispondono
+all'assegnazione ad un processo di una maggiore banda passante nell'accesso a
+disco rispetto agli altri senza però che questo possa bloccare indefinitamente
+l'accesso agli altri; con un concetto simile a quello dei valori di
+\textit{nice} per le priorità di processore. In questo caso esistono però
+soltanto otto diverse priorità, indicate da un valore numerico fra 0 e
+7,\footnote{come per \textit{nice} anche in questo caso un valore più basso
+ indica una priorità maggiore.} che sono assegnate ai singoli processi in
+maniera automatica a partire dal loro valore di \textit{nice}.\footnote{come
+ riportato nella documentazione il valore della priorità viene calcolato con
+ la formula: $\mathtt{prio}=(\mathtt{nice}+20)/5$.}
+
+Infine la classe di priorità \textit{real-time} \const{IOPRIO\_CLASS\_RT}
+ricalca le analoghe priorità di processore: un processo in questa classe ha
+sempre la precedenza nell'accesso a disco rispetto a tutti i processi di
+priorità inferiore, e pertanto è in grado di bloccare completamente 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 inferiori.
+
+Per manipolare il valori delle priorità di I/O sono state approntate delle
+opportune macro, in grado di estrarre i valori di priorità e la classe dai
+valori restituiti da \func{ioprio\_get} e di creare da questi un opportuno
+valore da passare a \func{ioprio\_set}, che si sono riportate in
+tab.~\ref{tab:IOsched_class_macro}.
+
+\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 un priorità come
+ restituito da \func{ioprio\_get} ottiene il
+ valore della classe.\\
+ \macro{IOPRIO\_PRIO\_DATA}\texttt{(\textit{value})}
+ & dato il valore di un priorità come
+ restituito da \func{ioprio\_get} ottiene 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}
+
+
+
+%TODO trattare le priorità di I/O
+% vedi man ioprio_set e Documentation/block/ioprio.txt
+
+%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
%%% Local Variables:
%%% mode: latex
%%% TeX-master: "gapil"
%%% End:
+% LocalWords: Documentation block syscall ioprio IPRIO CLASS